Merge "Makes Activity.addDumpable() a @TestApi"
diff --git a/Android.bp b/Android.bp
index 8d82b38..8bc5d7a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -77,7 +77,6 @@
         // Java/AIDL sources under frameworks/base
         ":framework-annotations",
         ":framework-blobstore-sources",
-        ":framework-bluetooth-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
         ":framework-connectivity-tiramisu-sources",
         ":framework-core-sources",
         ":framework-drm-sources",
@@ -297,6 +296,7 @@
     defaults: ["framework-aidl-export-defaults"],
     srcs: [
         ":framework-non-updatable-sources",
+        ":framework-bluetooth-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
         "core/java/**/*.logtags",
         ":apex-info-list",
     ],
@@ -602,6 +602,7 @@
     libs: [
         "art.module.public.api",
         "sdk_module-lib_current_framework-tethering",
+        "sdk_public_current_framework-bluetooth",
         // There are a few classes from modules used by the core that
         // need to be resolved by metalava. We use a prebuilt stub of the
         // full sdk to ensure we can resolve them. If a new class gets added,
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 3d6b52f..c50d446 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -102,6 +102,7 @@
 
         ":framework-appsearch-sources",
         ":framework-connectivity-sources",
+        ":framework-bluetooth-sources",
         ":framework-connectivity-tiramisu-updatable-sources",
         ":framework-graphics-srcs",
         ":framework-mediaprovider-sources",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 8a15758..a0a426e 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -215,52 +215,6 @@
 // from stub sources
 /////////////////////////////////////////////////////////////////////
 
-modules_public_stubs = [
-    "android.net.ipsec.ike.stubs",
-    "art.module.public.api.stubs",
-    "conscrypt.module.public.api.stubs",
-    "framework-appsearch.stubs",
-    "framework-connectivity.stubs",
-    "framework-connectivity-tiramisu.stubs",
-    "framework-graphics.stubs",
-    "framework-media.stubs",
-    "framework-mediaprovider.stubs",
-    "framework-nearby.stubs",
-    "framework-permission.stubs",
-    "framework-permission-s.stubs",
-    "framework-scheduling.stubs",
-    "framework-sdkextensions.stubs",
-    "framework-statsd.stubs",
-    "framework-supplementalprocess.stubs",
-    "framework-tethering.stubs",
-    "framework-uwb.stubs",
-    "framework-wifi.stubs",
-    "i18n.module.public.api.stubs",
-]
-
-modules_system_stubs = [
-    "android.net.ipsec.ike.stubs.system",
-    "art.module.public.api.stubs.system",
-    "conscrypt.module.public.api.stubs", // Only has public stubs
-    "framework-appsearch.stubs.system",
-    "framework-connectivity.stubs.system",
-    "framework-connectivity-tiramisu.stubs.system",
-    "framework-graphics.stubs.system",
-    "framework-media.stubs.system",
-    "framework-mediaprovider.stubs.system",
-    "framework-nearby.stubs.system",
-    "framework-permission.stubs.system",
-    "framework-permission-s.stubs.system",
-    "framework-scheduling.stubs.system",
-    "framework-sdkextensions.stubs.system",
-    "framework-statsd.stubs.system",
-    "framework-supplementalprocess.stubs",
-    "framework-tethering.stubs.system",
-    "framework-uwb.stubs.system",
-    "framework-wifi.stubs.system",
-    "i18n.module.public.api.stubs", // Only has public stubs
-]
-
 java_defaults {
     name: "android-non-updatable_defaults_stubs_current",
     libs: ["stub-annotations"],
@@ -282,14 +236,7 @@
     name: "android-non-updatable.stubs",
     defaults: ["android-non-updatable_defaults_stubs_current"],
     srcs: [":api-stubs-docs-non-updatable"],
-    libs: modules_public_stubs,
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            libs: [
-                "framework-supplementalapi.stubs",
-            ],
-        },
-    },
+    libs: ["all-modules-public-stubs"],
     dist: {
         dir: "apistubs/android/public",
     },
@@ -299,14 +246,7 @@
     name: "android-non-updatable.stubs.system",
     defaults: ["android-non-updatable_defaults_stubs_current"],
     srcs: [":system-api-stubs-docs-non-updatable"],
-    libs: modules_system_stubs,
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            libs: [
-                "framework-supplementalapi.stubs",
-            ],
-        },
-    },
+    libs: ["all-modules-system-stubs"],
     dist: {
         dir: "apistubs/android/system",
     },
@@ -318,6 +258,8 @@
     srcs: [":module-lib-api-stubs-docs-non-updatable"],
     libs: [
         "sdk_module-lib_current_framework-tethering",
+        "sdk_public_current_framework-bluetooth",
+        // NOTE: The below can be removed once the prebuilt stub contains bluetooth.
         "sdk_system_current_android",
         // NOTE: The below can be removed once the prebuilt stub contains IKE.
         "sdk_system_current_android.net.ipsec.ike",
@@ -331,14 +273,7 @@
     name: "android-non-updatable.stubs.test",
     defaults: ["android-non-updatable_defaults_stubs_current"],
     srcs: [":test-api-stubs-docs-non-updatable"],
-    libs: modules_system_stubs,
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            libs: [
-                "framework-supplementalapi.stubs",
-            ],
-        },
-    },
+    libs: ["all-modules-system-stubs"],
     dist: {
         dir: "apistubs/android/test",
     },
@@ -356,33 +291,21 @@
 
 java_library_with_nonpublic_deps {
     name: "android_stubs_current",
-    static_libs: modules_public_stubs + [
+    static_libs: [
+        "all-modules-public-stubs",
         "android-non-updatable.stubs",
         "private-stub-annotations-jar",
     ],
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            static_libs: [
-                "framework-supplementalapi.stubs",
-            ],
-        },
-    },
     defaults: ["android.jar_defaults"],
 }
 
 java_library_with_nonpublic_deps {
     name: "android_system_stubs_current",
-    static_libs: modules_system_stubs + [
+    static_libs: [
+        "all-modules-system-stubs",
         "android-non-updatable.stubs.system",
         "private-stub-annotations-jar",
     ],
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            static_libs: [
-                "framework-supplementalapi.stubs",
-            ],
-        },
-    },
     defaults: [
         "android.jar_defaults",
         "android_stubs_dists_default",
@@ -404,17 +327,11 @@
     name: "android_test_stubs_current",
     // Modules do not have test APIs, but we want to include their SystemApis, like we include
     // the SystemApi of framework-non-updatable-sources.
-    static_libs: modules_system_stubs + [
+    static_libs: [
+        "all-modules-system-stubs",
         "android-non-updatable.stubs.test",
         "private-stub-annotations-jar",
     ],
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            static_libs: [
-                "framework-supplementalapi.stubs",
-            ],
-        },
-    },
     defaults: [
         "android.jar_defaults",
         "android_stubs_dists_default",
diff --git a/api/Android.bp b/api/Android.bp
index a22c2f6..d8727f9 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -110,6 +110,7 @@
         "art.module.public.api",
         "conscrypt.module.public.api",
         "framework-appsearch",
+        "framework-bluetooth",
         "framework-connectivity",
         "framework-connectivity-tiramisu",
         "framework-graphics",
diff --git a/api/api.go b/api/api.go
index 4b6ebc1..aa9e399e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -27,6 +27,7 @@
 const art = "art.module.public.api"
 const conscrypt = "conscrypt.module.public.api"
 const i18n = "i18n.module.public.api"
+var modules_with_only_public_scope = []string{i18n, conscrypt}
 
 // The intention behind this soong plugin is to generate a number of "merged"
 // API-related modules that would otherwise require a large amount of very
@@ -183,6 +184,27 @@
 	ctx.CreateModule(genrule.GenRuleFactory, &props)
 }
 
+func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) {
+	props := libraryProps{}
+	props.Name = proptools.StringPtr("all-modules-public-stubs")
+	props.Static_libs = transformArray(modules, "", ".stubs")
+	props.Sdk_version = proptools.StringPtr("module_current")
+	props.Visibility = []string{"//frameworks/base"}
+	ctx.CreateModule(java.LibraryFactory, &props)
+}
+
+func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
+	props := libraryProps{}
+	modules_with_system_stubs := removeAll(modules, modules_with_only_public_scope)
+	props.Name = proptools.StringPtr("all-modules-system-stubs")
+	props.Static_libs = append(
+		transformArray(modules_with_only_public_scope, "", ".stubs"),
+		transformArray(modules_with_system_stubs, "", ".stubs.system")...)
+	props.Sdk_version = proptools.StringPtr("module_current")
+	props.Visibility = []string{"//frameworks/base"}
+	ctx.CreateModule(java.LibraryFactory, &props)
+}
+
 func createMergedModuleLibStubs(ctx android.LoadHookContext, modules []string) {
 	// The user of this module compiles against the "core" SDK, so remove core libraries to avoid dupes.
 	modules = removeAll(modules, []string{art, conscrypt, i18n})
@@ -205,7 +227,7 @@
 func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
 	var textFiles []MergedTxtDefinition
 	// Two module libraries currently do not support @SystemApi so only have the public scope.
-	bcpWithSystemApi := removeAll(bootclasspath, []string{conscrypt, i18n})
+	bcpWithSystemApi := removeAll(bootclasspath, modules_with_only_public_scope)
 
 	tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
 	for i, f := range []string{"current.txt", "removed.txt"} {
@@ -253,6 +275,8 @@
 
 	createMergedStubsSrcjar(ctx, bootclasspath)
 
+	createMergedPublicStubs(ctx, bootclasspath)
+	createMergedSystemStubs(ctx, bootclasspath)
 	createMergedModuleLibStubs(ctx, bootclasspath)
 
 	createMergedAnnotations(ctx, bootclasspath)
diff --git a/core/api/current.txt b/core/api/current.txt
index 5f83b33..0316875 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -50,6 +50,7 @@
     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_TV_INTERACTIVE_APP = "android.permission.BIND_TV_INTERACTIVE_APP";
     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";
@@ -7348,6 +7349,7 @@
     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 int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig();
     method public int getRequiredPasswordComplexity();
     method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
@@ -7492,6 +7494,7 @@
     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 setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean);
+    method public void setPreferentialNetworkServiceConfig(@NonNull android.app.admin.PreferentialNetworkServiceConfig);
     method public void setPreferentialNetworkServiceEnabled(boolean);
     method public void setProfileEnabled(@NonNull android.content.ComponentName);
     method public void setProfileName(@NonNull android.content.ComponentName, String);
@@ -7777,6 +7780,32 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
   }
 
+  public final class PreferentialNetworkServiceConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public int[] getExcludedUids();
+    method @NonNull public int[] getIncludedUids();
+    method public int getNetworkId();
+    method public boolean isEnabled();
+    method public boolean isFallbackToDefaultConnectionAllowed();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.PreferentialNetworkServiceConfig> CREATOR;
+    field public static final int PREFERENTIAL_NETWORK_ID_1 = 1; // 0x1
+    field public static final int PREFERENTIAL_NETWORK_ID_2 = 2; // 0x2
+    field public static final int PREFERENTIAL_NETWORK_ID_3 = 3; // 0x3
+    field public static final int PREFERENTIAL_NETWORK_ID_4 = 4; // 0x4
+    field public static final int PREFERENTIAL_NETWORK_ID_5 = 5; // 0x5
+  }
+
+  public static final class PreferentialNetworkServiceConfig.Builder {
+    ctor public PreferentialNetworkServiceConfig.Builder();
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig build();
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setEnabled(boolean);
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setExcludedUids(@NonNull int[]);
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setFallbackToDefaultConnectionAllowed(boolean);
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setIncludedUids(@NonNull int[]);
+    method @NonNull public android.app.admin.PreferentialNetworkServiceConfig.Builder setNetworkId(int);
+  }
+
   public class SecurityLog {
     ctor public SecurityLog();
     field public static final int LEVEL_ERROR = 3; // 0x3
@@ -8845,1364 +8874,6 @@
 
 }
 
-package android.bluetooth {
-
-  public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
-    method public void finalize();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 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 @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean cancelDiscovery();
-    method public static boolean checkBluetoothAddress(String);
-    method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, "android.permission.LOCAL_MAC_ADDRESS"}) public String getAddress();
-    method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
-    method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
-    method @Deprecated public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
-    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public java.time.Duration getDiscoverableTimeout();
-    method public int getLeMaximumAdvertisingDataLength();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getMaxConnectedAudioDevices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getProfileConnectionState(int);
-    method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
-    method public android.bluetooth.BluetoothDevice getRemoteDevice(String);
-    method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getScanMode();
-    method public int getState();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering();
-    method public boolean isEnabled();
-    method public boolean isLe2MPhySupported();
-    method public int isLeAudioBroadcastAssistantSupported();
-    method public int isLeAudioBroadcastSourceSupported();
-    method public int isLeAudioSupported();
-    method public boolean isLeCodedPhySupported();
-    method public boolean isLeExtendedAdvertisingSupported();
-    method public boolean isLePeriodicAdvertisingSupported();
-    method public boolean isMultipleAdvertisementSupported();
-    method public boolean isOffloadedFilteringSupported();
-    method public boolean isOffloadedScanBatchingSupported();
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setName(String);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startDiscovery();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) 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 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
-    field public static final int STATE_CONNECTED = 2; // 0x2
-    field public static final int STATE_CONNECTING = 1; // 0x1
-    field public static final int STATE_DISCONNECTED = 0; // 0x0
-    field public static final int STATE_DISCONNECTING = 3; // 0x3
-    field public static final int STATE_OFF = 10; // 0xa
-    field public static final int STATE_ON = 12; // 0xc
-    field public static final int STATE_TURNING_OFF = 13; // 0xd
-    field public static final int STATE_TURNING_ON = 11; // 0xb
-  }
-
-  public static interface BluetoothAdapter.LeScanCallback {
-    method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
-  }
-
-  public class BluetoothAssignedNumbers {
-    field public static final int AAMP_OF_AMERICA = 190; // 0xbe
-    field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a
-    field public static final int ACE_SENSOR = 188; // 0xbc
-    field public static final int ADIDAS = 195; // 0xc3
-    field public static final int ADVANCED_PANMOBIL_SYSTEMS = 145; // 0x91
-    field public static final int AIROHA_TECHNOLOGY = 148; // 0x94
-    field public static final int ALCATEL = 36; // 0x24
-    field public static final int ALPWISE = 154; // 0x9a
-    field public static final int AMICCOM_ELECTRONICS = 192; // 0xc0
-    field public static final int APLIX = 189; // 0xbd
-    field public static final int APPLE = 76; // 0x4c
-    field public static final int APT_LICENSING = 79; // 0x4f
-    field public static final int ARCHOS = 207; // 0xcf
-    field public static final int ARP_DEVICES = 168; // 0xa8
-    field public static final int ATHEROS_COMMUNICATIONS = 69; // 0x45
-    field public static final int ATMEL = 19; // 0x13
-    field public static final int AUSTCO_COMMUNICATION_SYSTEMS = 213; // 0xd5
-    field public static final int AUTONET_MOBILE = 127; // 0x7f
-    field public static final int AVAGO = 78; // 0x4e
-    field public static final int AVM_BERLIN = 31; // 0x1f
-    field public static final int A_AND_D_ENGINEERING = 105; // 0x69
-    field public static final int A_AND_R_CAMBRIDGE = 124; // 0x7c
-    field public static final int BANDSPEED = 32; // 0x20
-    field public static final int BAND_XI_INTERNATIONAL = 100; // 0x64
-    field public static final int BDE_TECHNOLOGY = 180; // 0xb4
-    field public static final int BEATS_ELECTRONICS = 204; // 0xcc
-    field public static final int BEAUTIFUL_ENTERPRISE = 108; // 0x6c
-    field public static final int BEKEY = 178; // 0xb2
-    field public static final int BELKIN_INTERNATIONAL = 92; // 0x5c
-    field public static final int BINAURIC = 203; // 0xcb
-    field public static final int BIOSENTRONICS = 219; // 0xdb
-    field public static final int BLUEGIGA = 71; // 0x47
-    field public static final int BLUERADIOS = 133; // 0x85
-    field public static final int BLUETOOTH_SIG = 63; // 0x3f
-    field public static final int BLUETREK_TECHNOLOGIES = 151; // 0x97
-    field public static final int BOSE = 158; // 0x9e
-    field public static final int BRIARTEK = 109; // 0x6d
-    field public static final int BROADCOM = 15; // 0xf
-    field public static final int CAEN_RFID = 170; // 0xaa
-    field public static final int CAMBRIDGE_SILICON_RADIO = 10; // 0xa
-    field public static final int CATC = 52; // 0x34
-    field public static final int CINETIX = 175; // 0xaf
-    field public static final int CLARINOX_TECHNOLOGIES = 179; // 0xb3
-    field public static final int COLORFY = 156; // 0x9c
-    field public static final int COMMIL = 51; // 0x33
-    field public static final int CONEXANT_SYSTEMS = 28; // 0x1c
-    field public static final int CONNECTBLUE = 113; // 0x71
-    field public static final int CONTINENTAL_AUTOMOTIVE = 75; // 0x4b
-    field public static final int CONWISE_TECHNOLOGY = 66; // 0x42
-    field public static final int CREATIVE_TECHNOLOGY = 118; // 0x76
-    field public static final int C_TECHNOLOGIES = 38; // 0x26
-    field public static final int DANLERS = 225; // 0xe1
-    field public static final int DELORME_PUBLISHING_COMPANY = 128; // 0x80
-    field public static final int DEXCOM = 208; // 0xd0
-    field public static final int DIALOG_SEMICONDUCTOR = 210; // 0xd2
-    field public static final int DIGIANSWER = 12; // 0xc
-    field public static final int ECLIPSE = 53; // 0x35
-    field public static final int ECOTEST = 136; // 0x88
-    field public static final int ELGATO_SYSTEMS = 206; // 0xce
-    field public static final int EM_MICROELECTRONIC_MARIN = 90; // 0x5a
-    field public static final int EQUINOX_AG = 134; // 0x86
-    field public static final int ERICSSON_TECHNOLOGY = 0; // 0x0
-    field public static final int EVLUMA = 201; // 0xc9
-    field public static final int FREE2MOVE = 83; // 0x53
-    field public static final int FUNAI_ELECTRIC = 144; // 0x90
-    field public static final int GARMIN_INTERNATIONAL = 135; // 0x87
-    field public static final int GCT_SEMICONDUCTOR = 45; // 0x2d
-    field public static final int GELO = 200; // 0xc8
-    field public static final int GENEQ = 194; // 0xc2
-    field public static final int GENERAL_MOTORS = 104; // 0x68
-    field public static final int GENNUM = 59; // 0x3b
-    field public static final int GEOFORCE = 157; // 0x9d
-    field public static final int GIBSON_GUITARS = 98; // 0x62
-    field public static final int GN_NETCOM = 103; // 0x67
-    field public static final int GN_RESOUND = 137; // 0x89
-    field public static final int GOOGLE = 224; // 0xe0
-    field public static final int GREEN_THROTTLE_GAMES = 172; // 0xac
-    field public static final int GROUP_SENSE = 115; // 0x73
-    field public static final int HANLYNN_TECHNOLOGIES = 123; // 0x7b
-    field public static final int HARMAN_INTERNATIONAL = 87; // 0x57
-    field public static final int HEWLETT_PACKARD = 101; // 0x65
-    field public static final int HITACHI = 41; // 0x29
-    field public static final int HOSIDEN = 221; // 0xdd
-    field public static final int IBM = 3; // 0x3
-    field public static final int INFINEON_TECHNOLOGIES = 9; // 0x9
-    field public static final int INGENIEUR_SYSTEMGRUPPE_ZAHN = 171; // 0xab
-    field public static final int INTEGRATED_SILICON_SOLUTION = 65; // 0x41
-    field public static final int INTEGRATED_SYSTEM_SOLUTION = 57; // 0x39
-    field public static final int INTEL = 2; // 0x2
-    field public static final int INVENTEL = 30; // 0x1e
-    field public static final int IPEXTREME = 61; // 0x3d
-    field public static final int I_TECH_DYNAMIC_GLOBAL_DISTRIBUTION = 153; // 0x99
-    field public static final int JAWBONE = 138; // 0x8a
-    field public static final int JIANGSU_TOPPOWER_AUTOMOTIVE_ELECTRONICS = 155; // 0x9b
-    field public static final int JOHNSON_CONTROLS = 185; // 0xb9
-    field public static final int J_AND_M = 82; // 0x52
-    field public static final int KAWANTECH = 212; // 0xd4
-    field public static final int KC_TECHNOLOGY = 22; // 0x16
-    field public static final int KENSINGTON_COMPUTER_PRODUCTS_GROUP = 160; // 0xa0
-    field public static final int LAIRD_TECHNOLOGIES = 119; // 0x77
-    field public static final int LESSWIRE = 121; // 0x79
-    field public static final int LG_ELECTRONICS = 196; // 0xc4
-    field public static final int LINAK = 164; // 0xa4
-    field public static final int LUCENT = 7; // 0x7
-    field public static final int LUDUS_HELSINKI = 132; // 0x84
-    field public static final int MACRONIX = 44; // 0x2c
-    field public static final int MAGNETI_MARELLI = 169; // 0xa9
-    field public static final int MANSELLA = 33; // 0x21
-    field public static final int MARVELL = 72; // 0x48
-    field public static final int MATSUSHITA_ELECTRIC = 58; // 0x3a
-    field public static final int MC10 = 202; // 0xca
-    field public static final int MEDIATEK = 70; // 0x46
-    field public static final int MESO_INTERNATIONAL = 182; // 0xb6
-    field public static final int META_WATCH = 163; // 0xa3
-    field public static final int MEWTEL_TECHNOLOGY = 47; // 0x2f
-    field public static final int MICOMMAND = 99; // 0x63
-    field public static final int MICROCHIP_TECHNOLOGY = 205; // 0xcd
-    field public static final int MICROSOFT = 6; // 0x6
-    field public static final int MINDTREE = 106; // 0x6a
-    field public static final int MISFIT_WEARABLES = 223; // 0xdf
-    field public static final int MITEL_SEMICONDUCTOR = 16; // 0x10
-    field public static final int MITSUBISHI_ELECTRIC = 20; // 0x14
-    field public static final int MOBILIAN_CORPORATION = 55; // 0x37
-    field public static final int MONSTER = 112; // 0x70
-    field public static final int MOTOROLA = 8; // 0x8
-    field public static final int MSTAR_SEMICONDUCTOR = 122; // 0x7a
-    field public static final int MUZIK = 222; // 0xde
-    field public static final int NEC = 34; // 0x22
-    field public static final int NEC_LIGHTING = 149; // 0x95
-    field public static final int NEWLOGIC = 23; // 0x17
-    field public static final int NIKE = 120; // 0x78
-    field public static final int NINE_SOLUTIONS = 102; // 0x66
-    field public static final int NOKIA_MOBILE_PHONES = 1; // 0x1
-    field public static final int NORDIC_SEMICONDUCTOR = 89; // 0x59
-    field public static final int NORWOOD_SYSTEMS = 46; // 0x2e
-    field public static final int ODM_TECHNOLOGY = 150; // 0x96
-    field public static final int OMEGAWAVE = 174; // 0xae
-    field public static final int ONSET_COMPUTER = 197; // 0xc5
-    field public static final int OPEN_INTERFACE = 39; // 0x27
-    field public static final int OTL_DYNAMICS = 165; // 0xa5
-    field public static final int PANDA_OCEAN = 166; // 0xa6
-    field public static final int PARROT = 67; // 0x43
-    field public static final int PARTHUS_TECHNOLOGIES = 14; // 0xe
-    field public static final int PASSIF_SEMICONDUCTOR = 176; // 0xb0
-    field public static final int PETER_SYSTEMTECHNIK = 173; // 0xad
-    field public static final int PHILIPS_SEMICONDUCTORS = 37; // 0x25
-    field public static final int PLANTRONICS = 85; // 0x55
-    field public static final int POLAR_ELECTRO = 107; // 0x6b
-    field public static final int POLAR_ELECTRO_EUROPE = 209; // 0xd1
-    field public static final int PROCTER_AND_GAMBLE = 220; // 0xdc
-    field public static final int QUALCOMM = 29; // 0x1d
-    field public static final int QUALCOMM_CONNECTED_EXPERIENCES = 216; // 0xd8
-    field public static final int QUALCOMM_INNOVATION_CENTER = 184; // 0xb8
-    field public static final int QUALCOMM_LABS = 140; // 0x8c
-    field public static final int QUALCOMM_TECHNOLOGIES = 215; // 0xd7
-    field public static final int QUINTIC = 142; // 0x8e
-    field public static final int QUUPPA = 199; // 0xc7
-    field public static final int RALINK_TECHNOLOGY = 91; // 0x5b
-    field public static final int RDA_MICROELECTRONICS = 97; // 0x61
-    field public static final int REALTEK_SEMICONDUCTOR = 93; // 0x5d
-    field public static final int RED_M = 50; // 0x32
-    field public static final int RENESAS_TECHNOLOGY = 54; // 0x36
-    field public static final int RESEARCH_IN_MOTION = 60; // 0x3c
-    field public static final int RF_MICRO_DEVICES = 40; // 0x28
-    field public static final int RIVIERAWAVES = 96; // 0x60
-    field public static final int ROHDE_AND_SCHWARZ = 25; // 0x19
-    field public static final int RTX_TELECOM = 21; // 0x15
-    field public static final int SAMSUNG_ELECTRONICS = 117; // 0x75
-    field public static final int SARIS_CYCLING_GROUP = 177; // 0xb1
-    field public static final int SEERS_TECHNOLOGY = 125; // 0x7d
-    field public static final int SEIKO_EPSON = 64; // 0x40
-    field public static final int SELFLY = 198; // 0xc6
-    field public static final int SEMILINK = 226; // 0xe2
-    field public static final int SENNHEISER_COMMUNICATIONS = 130; // 0x82
-    field public static final int SHANGHAI_SUPER_SMART_ELECTRONICS = 114; // 0x72
-    field public static final int SHENZHEN_EXCELSECU_DATA_TECHNOLOGY = 193; // 0xc1
-    field public static final int SIGNIA_TECHNOLOGIES = 27; // 0x1b
-    field public static final int SILICON_WAVE = 11; // 0xb
-    field public static final int SIRF_TECHNOLOGY = 80; // 0x50
-    field public static final int SOCKET_MOBILE = 68; // 0x44
-    field public static final int SONY_ERICSSON = 86; // 0x56
-    field public static final int SOUND_ID = 111; // 0x6f
-    field public static final int SPORTS_TRACKING_TECHNOLOGIES = 126; // 0x7e
-    field public static final int SR_MEDIZINELEKTRONIK = 161; // 0xa1
-    field public static final int STACCATO_COMMUNICATIONS = 77; // 0x4d
-    field public static final int STALMART_TECHNOLOGY = 191; // 0xbf
-    field public static final int STARKEY_LABORATORIES = 186; // 0xba
-    field public static final int STOLLMAN_E_PLUS_V = 143; // 0x8f
-    field public static final int STONESTREET_ONE = 94; // 0x5e
-    field public static final int ST_MICROELECTRONICS = 48; // 0x30
-    field public static final int SUMMIT_DATA_COMMUNICATIONS = 110; // 0x6e
-    field public static final int SUUNTO = 159; // 0x9f
-    field public static final int SWIRL_NETWORKS = 181; // 0xb5
-    field public static final int SYMBOL_TECHNOLOGIES = 42; // 0x2a
-    field public static final int SYNOPSYS = 49; // 0x31
-    field public static final int SYSTEMS_AND_CHIPS = 62; // 0x3e
-    field public static final int S_POWER_ELECTRONICS = 187; // 0xbb
-    field public static final int TAIXINGBANG_TECHNOLOGY = 211; // 0xd3
-    field public static final int TENOVIS = 43; // 0x2b
-    field public static final int TERAX = 56; // 0x38
-    field public static final int TEXAS_INSTRUMENTS = 13; // 0xd
-    field public static final int THINKOPTICS = 146; // 0x92
-    field public static final int THREECOM = 5; // 0x5
-    field public static final int THREE_DIJOY = 84; // 0x54
-    field public static final int THREE_DSP = 73; // 0x49
-    field public static final int TIMEKEEPING_SYSTEMS = 131; // 0x83
-    field public static final int TIMEX_GROUP_USA = 214; // 0xd6
-    field public static final int TOPCORN_POSITIONING_SYSTEMS = 139; // 0x8b
-    field public static final int TOSHIBA = 4; // 0x4
-    field public static final int TRANSILICA = 24; // 0x18
-    field public static final int TRELAB = 183; // 0xb7
-    field public static final int TTPCOM = 26; // 0x1a
-    field public static final int TXTR = 218; // 0xda
-    field public static final int TZERO_TECHNOLOGIES = 81; // 0x51
-    field public static final int UNIVERSAL_ELECTRONICS = 147; // 0x93
-    field public static final int VERTU = 162; // 0xa2
-    field public static final int VISTEON = 167; // 0xa7
-    field public static final int VIZIO = 88; // 0x58
-    field public static final int VOYETRA_TURTLE_BEACH = 217; // 0xd9
-    field public static final int WAVEPLUS_TECHNOLOGY = 35; // 0x23
-    field public static final int WICENTRIC = 95; // 0x5f
-    field public static final int WIDCOMM = 17; // 0x11
-    field public static final int WUXI_VIMICRO = 129; // 0x81
-    field public static final int ZEEVO = 18; // 0x12
-    field public static final int ZER01_TV = 152; // 0x98
-    field public static final int ZOMM = 116; // 0x74
-    field public static final int ZSCAN_SOFTWARE = 141; // 0x8d
-  }
-
-  public final class BluetoothClass implements android.os.Parcelable {
-    method public int describeContents();
-    method public boolean doesClassMatch(int);
-    method public int getDeviceClass();
-    method public int getMajorDeviceClass();
-    method public boolean hasService(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothClass> CREATOR;
-    field public static final int PROFILE_A2DP = 1; // 0x1
-    field public static final int PROFILE_HEADSET = 0; // 0x0
-    field public static final int PROFILE_HID = 3; // 0x3
-  }
-
-  public static class BluetoothClass.Device {
-    ctor public BluetoothClass.Device();
-    field public static final int AUDIO_VIDEO_CAMCORDER = 1076; // 0x434
-    field public static final int AUDIO_VIDEO_CAR_AUDIO = 1056; // 0x420
-    field public static final int AUDIO_VIDEO_HANDSFREE = 1032; // 0x408
-    field public static final int AUDIO_VIDEO_HEADPHONES = 1048; // 0x418
-    field public static final int AUDIO_VIDEO_HIFI_AUDIO = 1064; // 0x428
-    field public static final int AUDIO_VIDEO_LOUDSPEAKER = 1044; // 0x414
-    field public static final int AUDIO_VIDEO_MICROPHONE = 1040; // 0x410
-    field public static final int AUDIO_VIDEO_PORTABLE_AUDIO = 1052; // 0x41c
-    field public static final int AUDIO_VIDEO_SET_TOP_BOX = 1060; // 0x424
-    field public static final int AUDIO_VIDEO_UNCATEGORIZED = 1024; // 0x400
-    field public static final int AUDIO_VIDEO_VCR = 1068; // 0x42c
-    field public static final int AUDIO_VIDEO_VIDEO_CAMERA = 1072; // 0x430
-    field public static final int AUDIO_VIDEO_VIDEO_CONFERENCING = 1088; // 0x440
-    field public static final int AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 1084; // 0x43c
-    field public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY = 1096; // 0x448
-    field public static final int AUDIO_VIDEO_VIDEO_MONITOR = 1080; // 0x438
-    field public static final int AUDIO_VIDEO_WEARABLE_HEADSET = 1028; // 0x404
-    field public static final int COMPUTER_DESKTOP = 260; // 0x104
-    field public static final int COMPUTER_HANDHELD_PC_PDA = 272; // 0x110
-    field public static final int COMPUTER_LAPTOP = 268; // 0x10c
-    field public static final int COMPUTER_PALM_SIZE_PC_PDA = 276; // 0x114
-    field public static final int COMPUTER_SERVER = 264; // 0x108
-    field public static final int COMPUTER_UNCATEGORIZED = 256; // 0x100
-    field public static final int COMPUTER_WEARABLE = 280; // 0x118
-    field public static final int HEALTH_BLOOD_PRESSURE = 2308; // 0x904
-    field public static final int HEALTH_DATA_DISPLAY = 2332; // 0x91c
-    field public static final int HEALTH_GLUCOSE = 2320; // 0x910
-    field public static final int HEALTH_PULSE_OXIMETER = 2324; // 0x914
-    field public static final int HEALTH_PULSE_RATE = 2328; // 0x918
-    field public static final int HEALTH_THERMOMETER = 2312; // 0x908
-    field public static final int HEALTH_UNCATEGORIZED = 2304; // 0x900
-    field public static final int HEALTH_WEIGHING = 2316; // 0x90c
-    field public static final int PHONE_CELLULAR = 516; // 0x204
-    field public static final int PHONE_CORDLESS = 520; // 0x208
-    field public static final int PHONE_ISDN = 532; // 0x214
-    field public static final int PHONE_MODEM_OR_GATEWAY = 528; // 0x210
-    field public static final int PHONE_SMART = 524; // 0x20c
-    field public static final int PHONE_UNCATEGORIZED = 512; // 0x200
-    field public static final int TOY_CONTROLLER = 2064; // 0x810
-    field public static final int TOY_DOLL_ACTION_FIGURE = 2060; // 0x80c
-    field public static final int TOY_GAME = 2068; // 0x814
-    field public static final int TOY_ROBOT = 2052; // 0x804
-    field public static final int TOY_UNCATEGORIZED = 2048; // 0x800
-    field public static final int TOY_VEHICLE = 2056; // 0x808
-    field public static final int WEARABLE_GLASSES = 1812; // 0x714
-    field public static final int WEARABLE_HELMET = 1808; // 0x710
-    field public static final int WEARABLE_JACKET = 1804; // 0x70c
-    field public static final int WEARABLE_PAGER = 1800; // 0x708
-    field public static final int WEARABLE_UNCATEGORIZED = 1792; // 0x700
-    field public static final int WEARABLE_WRIST_WATCH = 1796; // 0x704
-  }
-
-  public static class BluetoothClass.Device.Major {
-    ctor public BluetoothClass.Device.Major();
-    field public static final int AUDIO_VIDEO = 1024; // 0x400
-    field public static final int COMPUTER = 256; // 0x100
-    field public static final int HEALTH = 2304; // 0x900
-    field public static final int IMAGING = 1536; // 0x600
-    field public static final int MISC = 0; // 0x0
-    field public static final int NETWORKING = 768; // 0x300
-    field public static final int PERIPHERAL = 1280; // 0x500
-    field public static final int PHONE = 512; // 0x200
-    field public static final int TOY = 2048; // 0x800
-    field public static final int UNCATEGORIZED = 7936; // 0x1f00
-    field public static final int WEARABLE = 1792; // 0x700
-  }
-
-  public static final class BluetoothClass.Service {
-    ctor public BluetoothClass.Service();
-    field public static final int AUDIO = 2097152; // 0x200000
-    field public static final int CAPTURE = 524288; // 0x80000
-    field public static final int INFORMATION = 8388608; // 0x800000
-    field public static final int LE_AUDIO = 16384; // 0x4000
-    field public static final int LIMITED_DISCOVERABILITY = 8192; // 0x2000
-    field public static final int NETWORKING = 131072; // 0x20000
-    field public static final int OBJECT_TRANSFER = 1048576; // 0x100000
-    field public static final int POSITIONING = 65536; // 0x10000
-    field public static final int RENDER = 262144; // 0x40000
-    field public static final int TELEPHONY = 4194304; // 0x400000
-  }
-
-  public final class BluetoothCodecConfig implements android.os.Parcelable {
-    ctor public BluetoothCodecConfig(int);
-    method public int describeContents();
-    method public int getBitsPerSample();
-    method public int getChannelMode();
-    method public int getCodecPriority();
-    method public long getCodecSpecific1();
-    method public long getCodecSpecific2();
-    method public long getCodecSpecific3();
-    method public long getCodecSpecific4();
-    method public int getCodecType();
-    method public static int getMaxCodecType();
-    method public int getSampleRate();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1
-    field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2
-    field public static final int BITS_PER_SAMPLE_32 = 4; // 0x4
-    field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0
-    field public static final int CHANNEL_MODE_MONO = 1; // 0x1
-    field public static final int CHANNEL_MODE_NONE = 0; // 0x0
-    field public static final int CHANNEL_MODE_STEREO = 2; // 0x2
-    field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
-    field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
-    field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR;
-    field public static final int SAMPLE_RATE_176400 = 16; // 0x10
-    field public static final int SAMPLE_RATE_192000 = 32; // 0x20
-    field public static final int SAMPLE_RATE_44100 = 1; // 0x1
-    field public static final int SAMPLE_RATE_48000 = 2; // 0x2
-    field public static final int SAMPLE_RATE_88200 = 4; // 0x4
-    field public static final int SAMPLE_RATE_96000 = 8; // 0x8
-    field public static final int SAMPLE_RATE_NONE = 0; // 0x0
-    field public static final int SOURCE_CODEC_TYPE_AAC = 1; // 0x1
-    field public static final int SOURCE_CODEC_TYPE_APTX = 2; // 0x2
-    field public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; // 0x3
-    field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
-    field public static final int SOURCE_CODEC_TYPE_LC3 = 5; // 0x5
-    field public static final int SOURCE_CODEC_TYPE_LDAC = 4; // 0x4
-    field public static final int SOURCE_CODEC_TYPE_SBC = 0; // 0x0
-  }
-
-  public static final class BluetoothCodecConfig.Builder {
-    ctor public BluetoothCodecConfig.Builder();
-    method @NonNull public android.bluetooth.BluetoothCodecConfig build();
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setBitsPerSample(int);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setChannelMode(int);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecPriority(int);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific1(long);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific2(long);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific3(long);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific4(long);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecType(int);
-    method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setSampleRate(int);
-  }
-
-  public final class BluetoothCodecStatus implements android.os.Parcelable {
-    ctor public BluetoothCodecStatus(@Nullable android.bluetooth.BluetoothCodecConfig, @Nullable java.util.List<android.bluetooth.BluetoothCodecConfig>, @Nullable java.util.List<android.bluetooth.BluetoothCodecConfig>);
-    method public int describeContents();
-    method @Nullable public android.bluetooth.BluetoothCodecConfig getCodecConfig();
-    method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getCodecsLocalCapabilities();
-    method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getCodecsSelectableCapabilities();
-    method public boolean isCodecConfigSelectable(@Nullable android.bluetooth.BluetoothCodecConfig);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecStatus> CREATOR;
-    field public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS";
-  }
-
-  public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method public void close();
-    method protected void finalize();
-    method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
-    method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED = "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothDevice implements android.os.Parcelable {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBond();
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
-    method public int describeContents();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean fetchUuidsWithSdp();
-    method public String getAddress();
-    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getAlias();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothClass getBluetoothClass();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getBondState();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getType();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelUuid[] getUuids();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int setAlias(@Nullable String);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setPairingConfirmation(boolean);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPin(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.device.action.ALIAS_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
-    field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
-    field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
-    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
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothDevice> CREATOR;
-    field public static final int DEVICE_TYPE_CLASSIC = 1; // 0x1
-    field public static final int DEVICE_TYPE_DUAL = 3; // 0x3
-    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 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_IS_COORDINATED_SET_MEMBER = "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
-    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
-    field public static final int PHY_LE_1M_MASK = 1; // 0x1
-    field public static final int PHY_LE_2M = 2; // 0x2
-    field public static final int PHY_LE_2M_MASK = 2; // 0x2
-    field public static final int PHY_LE_CODED = 3; // 0x3
-    field public static final int PHY_LE_CODED_MASK = 4; // 0x4
-    field public static final int PHY_OPTION_NO_PREFERRED = 0; // 0x0
-    field public static final int PHY_OPTION_S2 = 1; // 0x1
-    field public static final int PHY_OPTION_S8 = 2; // 0x2
-    field public static final int TRANSPORT_AUTO = 0; // 0x0
-    field public static final int TRANSPORT_BREDR = 1; // 0x1
-    field public static final int TRANSPORT_LE = 2; // 0x2
-  }
-
-  public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean beginReliableWrite();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void close();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void disconnect();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean discoverServices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean executeReliableWrite();
-    method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @Deprecated public int getConnectionState(android.bluetooth.BluetoothDevice);
-    method public android.bluetooth.BluetoothDevice getDevice();
-    method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
-    method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readRemoteRssi();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestConnectionPriority(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeCharacteristic(@NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeDescriptor(@NonNull android.bluetooth.BluetoothGattDescriptor, @NonNull byte[]);
-    field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0
-    field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1
-    field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2
-    field public static final int GATT_CONNECTION_CONGESTED = 143; // 0x8f
-    field public static final int GATT_FAILURE = 257; // 0x101
-    field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5
-    field public static final int GATT_INSUFFICIENT_AUTHORIZATION = 8; // 0x8
-    field public static final int GATT_INSUFFICIENT_ENCRYPTION = 15; // 0xf
-    field public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 13; // 0xd
-    field public static final int GATT_INVALID_OFFSET = 7; // 0x7
-    field public static final int GATT_READ_NOT_PERMITTED = 2; // 0x2
-    field public static final int GATT_REQUEST_NOT_SUPPORTED = 6; // 0x6
-    field public static final int GATT_SUCCESS = 0; // 0x0
-    field public static final int GATT_WRITE_NOT_PERMITTED = 3; // 0x3
-  }
-
-  public abstract class BluetoothGattCallback {
-    ctor public BluetoothGattCallback();
-    method @Deprecated public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic);
-    method public void onCharacteristicChanged(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[]);
-    method @Deprecated public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
-    method public void onCharacteristicRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int);
-    method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
-    method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int);
-    method @Deprecated public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
-    method public void onDescriptorRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattDescriptor, int, @NonNull byte[]);
-    method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
-    method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int);
-    method public void onPhyRead(android.bluetooth.BluetoothGatt, int, int, int);
-    method public void onPhyUpdate(android.bluetooth.BluetoothGatt, int, int, int);
-    method public void onReadRemoteRssi(android.bluetooth.BluetoothGatt, int, int);
-    method public void onReliableWriteCompleted(android.bluetooth.BluetoothGatt, int);
-    method public void onServiceChanged(@NonNull android.bluetooth.BluetoothGatt);
-    method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
-  }
-
-  public class BluetoothGattCharacteristic implements android.os.Parcelable {
-    ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
-    method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
-    method public int describeContents();
-    method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
-    method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
-    method @Deprecated public Float getFloatValue(int, int);
-    method public int getInstanceId();
-    method @Deprecated public Integer getIntValue(int, int);
-    method public int getPermissions();
-    method public int getProperties();
-    method public android.bluetooth.BluetoothGattService getService();
-    method @Deprecated public String getStringValue(int);
-    method public java.util.UUID getUuid();
-    method @Deprecated public byte[] getValue();
-    method public int getWriteType();
-    method @Deprecated public boolean setValue(byte[]);
-    method @Deprecated public boolean setValue(int, int, int);
-    method @Deprecated public boolean setValue(int, int, int, int);
-    method @Deprecated public boolean setValue(String);
-    method public void setWriteType(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
-    field public static final int FORMAT_FLOAT = 52; // 0x34
-    field public static final int FORMAT_SFLOAT = 50; // 0x32
-    field public static final int FORMAT_SINT16 = 34; // 0x22
-    field public static final int FORMAT_SINT32 = 36; // 0x24
-    field public static final int FORMAT_SINT8 = 33; // 0x21
-    field public static final int FORMAT_UINT16 = 18; // 0x12
-    field public static final int FORMAT_UINT32 = 20; // 0x14
-    field public static final int FORMAT_UINT8 = 17; // 0x11
-    field public static final int PERMISSION_READ = 1; // 0x1
-    field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
-    field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
-    field public static final int PERMISSION_WRITE = 16; // 0x10
-    field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
-    field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
-    field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
-    field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
-    field public static final int PROPERTY_BROADCAST = 1; // 0x1
-    field public static final int PROPERTY_EXTENDED_PROPS = 128; // 0x80
-    field public static final int PROPERTY_INDICATE = 32; // 0x20
-    field public static final int PROPERTY_NOTIFY = 16; // 0x10
-    field public static final int PROPERTY_READ = 2; // 0x2
-    field public static final int PROPERTY_SIGNED_WRITE = 64; // 0x40
-    field public static final int PROPERTY_WRITE = 8; // 0x8
-    field public static final int PROPERTY_WRITE_NO_RESPONSE = 4; // 0x4
-    field public static final int WRITE_TYPE_DEFAULT = 2; // 0x2
-    field public static final int WRITE_TYPE_NO_RESPONSE = 1; // 0x1
-    field public static final int WRITE_TYPE_SIGNED = 4; // 0x4
-    field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors;
-  }
-
-  public class BluetoothGattDescriptor implements android.os.Parcelable {
-    ctor public BluetoothGattDescriptor(java.util.UUID, int);
-    method public int describeContents();
-    method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
-    method public int getPermissions();
-    method public java.util.UUID getUuid();
-    method @Deprecated public byte[] getValue();
-    method @Deprecated public boolean setValue(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
-    field public static final byte[] DISABLE_NOTIFICATION_VALUE;
-    field public static final byte[] ENABLE_INDICATION_VALUE;
-    field public static final byte[] ENABLE_NOTIFICATION_VALUE;
-    field public static final int PERMISSION_READ = 1; // 0x1
-    field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
-    field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
-    field public static final int PERMISSION_WRITE = 16; // 0x10
-    field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
-    field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
-    field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
-    field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
-  }
-
-  public final class BluetoothGattServer implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean addService(android.bluetooth.BluetoothGattService);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void cancelConnection(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void clearServices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void close();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(android.bluetooth.BluetoothDevice, boolean);
-    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.bluetooth.BluetoothGattService getService(java.util.UUID);
-    method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int notifyCharacteristicChanged(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothGattCharacteristic, boolean, @NonNull byte[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeService(android.bluetooth.BluetoothGattService);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(android.bluetooth.BluetoothDevice, int, int, int);
-  }
-
-  public abstract class BluetoothGattServerCallback {
-    ctor public BluetoothGattServerCallback();
-    method public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattCharacteristic);
-    method public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattCharacteristic, boolean, boolean, int, byte[]);
-    method public void onConnectionStateChange(android.bluetooth.BluetoothDevice, int, int);
-    method public void onDescriptorReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattDescriptor);
-    method public void onDescriptorWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattDescriptor, boolean, boolean, int, byte[]);
-    method public void onExecuteWrite(android.bluetooth.BluetoothDevice, int, boolean);
-    method public void onMtuChanged(android.bluetooth.BluetoothDevice, int);
-    method public void onNotificationSent(android.bluetooth.BluetoothDevice, int);
-    method public void onPhyRead(android.bluetooth.BluetoothDevice, int, int, int);
-    method public void onPhyUpdate(android.bluetooth.BluetoothDevice, int, int, int);
-    method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
-  }
-
-  public class BluetoothGattService implements android.os.Parcelable {
-    ctor public BluetoothGattService(java.util.UUID, int);
-    method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
-    method public boolean addService(android.bluetooth.BluetoothGattService);
-    method public int describeContents();
-    method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
-    method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
-    method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
-    method public int getInstanceId();
-    method public int getType();
-    method public java.util.UUID getUuid();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattService> CREATOR;
-    field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
-    field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
-    field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics;
-    field protected java.util.List<android.bluetooth.BluetoothGattService> mIncludedServices;
-  }
-
-  public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isNoiseReductionSupported(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isVoiceRecognitionSupported(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, String, String);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 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 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 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";
-  }
-
-  @Deprecated public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean registerSinkAppConfiguration(String, int, android.bluetooth.BluetoothHealthCallback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 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 {
-    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 @NonNull 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 @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean reportError(android.bluetooth.BluetoothDevice, byte);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean unregisterApp();
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 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
-    field public static final byte ERROR_RSP_SUCCESS = 0; // 0x0
-    field public static final byte ERROR_RSP_UNKNOWN = 14; // 0xe
-    field public static final byte ERROR_RSP_UNSUPPORTED_REQ = 3; // 0x3
-    field public static final byte PROTOCOL_BOOT_MODE = 0; // 0x0
-    field public static final byte PROTOCOL_REPORT_MODE = 1; // 0x1
-    field public static final byte REPORT_TYPE_FEATURE = 3; // 0x3
-    field public static final byte REPORT_TYPE_INPUT = 1; // 0x1
-    field public static final byte REPORT_TYPE_OUTPUT = 2; // 0x2
-    field public static final byte SUBCLASS1_COMBO = -64; // 0xffffffc0
-    field public static final byte SUBCLASS1_KEYBOARD = 64; // 0x40
-    field public static final byte SUBCLASS1_MOUSE = -128; // 0xffffff80
-    field public static final byte SUBCLASS1_NONE = 0; // 0x0
-    field public static final byte SUBCLASS2_CARD_READER = 6; // 0x6
-    field public static final byte SUBCLASS2_DIGITIZER_TABLET = 5; // 0x5
-    field public static final byte SUBCLASS2_GAMEPAD = 2; // 0x2
-    field public static final byte SUBCLASS2_JOYSTICK = 1; // 0x1
-    field public static final byte SUBCLASS2_REMOTE_CONTROL = 3; // 0x3
-    field public static final byte SUBCLASS2_SENSING_DEVICE = 4; // 0x4
-    field public static final byte SUBCLASS2_UNCATEGORIZED = 0; // 0x0
-  }
-
-  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);
-    method public void onGetReport(android.bluetooth.BluetoothDevice, byte, byte, int);
-    method public void onInterruptData(android.bluetooth.BluetoothDevice, byte, byte[]);
-    method public void onSetProtocol(android.bluetooth.BluetoothDevice, byte);
-    method public void onSetReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
-    method public void onVirtualCableUnplug(android.bluetooth.BluetoothDevice);
-  }
-
-  public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable {
-    ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int);
-    method public int describeContents();
-    method public int getDelayVariation();
-    method public int getLatency();
-    method public int getPeakBandwidth();
-    method public int getServiceType();
-    method public int getTokenBucketSize();
-    method public int getTokenRate();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR;
-    field public static final int MAX = -1; // 0xffffffff
-    field public static final int SERVICE_BEST_EFFORT = 1; // 0x1
-    field public static final int SERVICE_GUARANTEED = 2; // 0x2
-    field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0
-  }
-
-  public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
-    ctor public BluetoothHidDeviceAppSdpSettings(String, String, String, byte, byte[]);
-    method public int describeContents();
-    method public String getDescription();
-    method public byte[] getDescriptors();
-    method public String getName();
-    method public String getProvider();
-    method public byte getSubclass();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
-  }
-
-  public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method public void close();
-    method protected void finalize();
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothDevice getConnectedGroupLeadDevice(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getGroupId(@NonNull android.bluetooth.BluetoothDevice);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothLeAudioCodecConfig implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getBitsPerSample();
-    method public int getChannelMode();
-    method @NonNull public String getCodecName();
-    method public int getCodecPriority();
-    method public int getCodecType();
-    method public int getFrameDuration();
-    method public static int getMaxCodecType();
-    method public int getOctetsPerFrame();
-    method public int getSampleRate();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1
-    field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2
-    field public static final int BITS_PER_SAMPLE_32 = 3; // 0x3
-    field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0
-    field public static final int CHANNEL_MODE_MONO = 1; // 0x1
-    field public static final int CHANNEL_MODE_NONE = 0; // 0x0
-    field public static final int CHANNEL_MODE_STEREO = 2; // 0x2
-    field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
-    field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
-    field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothLeAudioCodecConfig> CREATOR;
-    field public static final int FRAME_DURATION_10000 = 2; // 0x2
-    field public static final int FRAME_DURATION_7500 = 1; // 0x1
-    field public static final int FRAME_DURATION_NONE = 0; // 0x0
-    field public static final int SAMPLE_RATE_16000 = 2; // 0x2
-    field public static final int SAMPLE_RATE_24000 = 3; // 0x3
-    field public static final int SAMPLE_RATE_32000 = 4; // 0x4
-    field public static final int SAMPLE_RATE_44100 = 5; // 0x5
-    field public static final int SAMPLE_RATE_48000 = 6; // 0x6
-    field public static final int SAMPLE_RATE_8000 = 1; // 0x1
-    field public static final int SAMPLE_RATE_NONE = 0; // 0x0
-    field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
-    field public static final int SOURCE_CODEC_TYPE_LC3 = 0; // 0x0
-  }
-
-  public static final class BluetoothLeAudioCodecConfig.Builder {
-    ctor public BluetoothLeAudioCodecConfig.Builder();
-    ctor public BluetoothLeAudioCodecConfig.Builder(@NonNull android.bluetooth.BluetoothLeAudioCodecConfig);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig build();
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setBitsPerSample(int);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setChannelMode(int);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setCodecPriority(int);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setCodecType(int);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setFrameDuration(int);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setOctetsPerFrame(int);
-    method @NonNull public android.bluetooth.BluetoothLeAudioCodecConfig.Builder setSampleRate(int);
-  }
-
-  public final class BluetoothManager {
-    method public android.bluetooth.BluetoothAdapter getAdapter();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice, int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
-  }
-
-  public interface 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[]);
-    field public static final int A2DP = 2; // 0x2
-    field public static final int CSIP_SET_COORDINATOR = 25; // 0x19
-    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 HAP_CLIENT = 28; // 0x1c
-    field public static final int HEADSET = 1; // 0x1
-    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 LE_AUDIO = 22; // 0x16
-    field public static final int SAP = 10; // 0xa
-    field public static final int STATE_CONNECTED = 2; // 0x2
-    field public static final int STATE_CONNECTING = 1; // 0x1
-    field public static final int STATE_DISCONNECTED = 0; // 0x0
-    field public static final int STATE_DISCONNECTING = 3; // 0x3
-  }
-
-  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 {
-    method public android.bluetooth.BluetoothSocket accept() throws java.io.IOException;
-    method public android.bluetooth.BluetoothSocket accept(int) throws java.io.IOException;
-    method public void close() throws java.io.IOException;
-    method public int getPsm();
-  }
-
-  public final class BluetoothSocket implements java.io.Closeable {
-    method public void close() throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void connect() throws java.io.IOException;
-    method public int getConnectionType();
-    method public java.io.InputStream getInputStream() throws java.io.IOException;
-    method public int getMaxReceivePacketSize();
-    method public int getMaxTransmitPacketSize();
-    method public java.io.OutputStream getOutputStream() throws java.io.IOException;
-    method public android.bluetooth.BluetoothDevice getRemoteDevice();
-    method public boolean isConnected();
-    field public static final int TYPE_L2CAP = 3; // 0x3
-    field public static final int TYPE_RFCOMM = 1; // 0x1
-    field public static final int TYPE_SCO = 2; // 0x2
-  }
-
-  public final class BluetoothStatusCodes {
-    field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2
-    field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1
-    field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3
-    field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200; // 0xc8
-    field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201; // 0xc9
-    field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6
-    field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8
-    field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9
-    field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
-    field public static final int FEATURE_NOT_SUPPORTED = 11; // 0xb
-    field public static final int FEATURE_SUPPORTED = 10; // 0xa
-    field public static final int SUCCESS = 0; // 0x0
-  }
-
-}
-
-package android.bluetooth.le {
-
-  public abstract class AdvertiseCallback {
-    ctor public AdvertiseCallback();
-    method public void onStartFailure(int);
-    method public void onStartSuccess(android.bluetooth.le.AdvertiseSettings);
-    field public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; // 0x3
-    field public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1; // 0x1
-    field public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; // 0x5
-    field public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4; // 0x4
-    field public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2; // 0x2
-  }
-
-  public final class AdvertiseData implements android.os.Parcelable {
-    method public int describeContents();
-    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 @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
-    method public java.util.List<android.os.ParcelUuid> getServiceUuids();
-    method @NonNull public java.util.List<android.bluetooth.le.TransportDiscoveryData> getTransportDiscoveryData();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
-  }
-
-  public static final class AdvertiseData.Builder {
-    ctor public AdvertiseData.Builder();
-    method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]);
-    method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
-    method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid);
-    method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
-    method @NonNull public android.bluetooth.le.AdvertiseData.Builder addTransportDiscoveryData(@NonNull android.bluetooth.le.TransportDiscoveryData);
-    method public android.bluetooth.le.AdvertiseData build();
-    method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
-    method public android.bluetooth.le.AdvertiseData.Builder setIncludeTxPowerLevel(boolean);
-  }
-
-  public final class AdvertiseSettings implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getMode();
-    method public int getTimeout();
-    method public int getTxPowerLevel();
-    method public boolean isConnectable();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int ADVERTISE_MODE_BALANCED = 1; // 0x1
-    field public static final int ADVERTISE_MODE_LOW_LATENCY = 2; // 0x2
-    field public static final int ADVERTISE_MODE_LOW_POWER = 0; // 0x0
-    field public static final int ADVERTISE_TX_POWER_HIGH = 3; // 0x3
-    field public static final int ADVERTISE_TX_POWER_LOW = 1; // 0x1
-    field public static final int ADVERTISE_TX_POWER_MEDIUM = 2; // 0x2
-    field public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0; // 0x0
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseSettings> CREATOR;
-  }
-
-  public static final class AdvertiseSettings.Builder {
-    ctor public AdvertiseSettings.Builder();
-    method public android.bluetooth.le.AdvertiseSettings build();
-    method public android.bluetooth.le.AdvertiseSettings.Builder setAdvertiseMode(int);
-    method public android.bluetooth.le.AdvertiseSettings.Builder setConnectable(boolean);
-    method public android.bluetooth.le.AdvertiseSettings.Builder setTimeout(int);
-    method public android.bluetooth.le.AdvertiseSettings.Builder setTxPowerLevel(int);
-  }
-
-  public final class AdvertisingSet {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void enableAdvertising(boolean, int, int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setScanResponseData(android.bluetooth.le.AdvertiseData);
-  }
-
-  public abstract class AdvertisingSetCallback {
-    ctor public AdvertisingSetCallback();
-    method public void onAdvertisingDataSet(android.bluetooth.le.AdvertisingSet, int);
-    method public void onAdvertisingEnabled(android.bluetooth.le.AdvertisingSet, boolean, int);
-    method public void onAdvertisingParametersUpdated(android.bluetooth.le.AdvertisingSet, int, int);
-    method public void onAdvertisingSetStarted(android.bluetooth.le.AdvertisingSet, int, int);
-    method public void onAdvertisingSetStopped(android.bluetooth.le.AdvertisingSet);
-    method public void onPeriodicAdvertisingDataSet(android.bluetooth.le.AdvertisingSet, int);
-    method public void onPeriodicAdvertisingEnabled(android.bluetooth.le.AdvertisingSet, boolean, int);
-    method public void onPeriodicAdvertisingParametersUpdated(android.bluetooth.le.AdvertisingSet, int);
-    method public void onScanResponseDataSet(android.bluetooth.le.AdvertisingSet, int);
-    field public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; // 0x3
-    field public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1; // 0x1
-    field public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; // 0x5
-    field public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4; // 0x4
-    field public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2; // 0x2
-    field public static final int ADVERTISE_SUCCESS = 0; // 0x0
-  }
-
-  public final class AdvertisingSetParameters implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getInterval();
-    method public int getPrimaryPhy();
-    method public int getSecondaryPhy();
-    method public int getTxPowerLevel();
-    method public boolean includeTxPower();
-    method public boolean isAnonymous();
-    method public boolean isConnectable();
-    method public boolean isLegacy();
-    method public boolean isScannable();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertisingSetParameters> CREATOR;
-    field public static final int INTERVAL_HIGH = 1600; // 0x640
-    field public static final int INTERVAL_LOW = 160; // 0xa0
-    field public static final int INTERVAL_MAX = 16777215; // 0xffffff
-    field public static final int INTERVAL_MEDIUM = 400; // 0x190
-    field public static final int INTERVAL_MIN = 160; // 0xa0
-    field public static final int TX_POWER_HIGH = 1; // 0x1
-    field public static final int TX_POWER_LOW = -15; // 0xfffffff1
-    field public static final int TX_POWER_MAX = 1; // 0x1
-    field public static final int TX_POWER_MEDIUM = -7; // 0xfffffff9
-    field public static final int TX_POWER_MIN = -127; // 0xffffff81
-    field public static final int TX_POWER_ULTRA_LOW = -21; // 0xffffffeb
-  }
-
-  public static final class AdvertisingSetParameters.Builder {
-    ctor public AdvertisingSetParameters.Builder();
-    method public android.bluetooth.le.AdvertisingSetParameters build();
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setAnonymous(boolean);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setConnectable(boolean);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setIncludeTxPower(boolean);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setInterval(int);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setScannable(boolean);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int);
-    method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int);
-  }
-
-  public final class BluetoothLeAdvertiser {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
-  }
-
-  public final class BluetoothLeScanner {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startScan(android.bluetooth.le.ScanCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) 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_SCAN) public void stopScan(android.bluetooth.le.ScanCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) 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 {
-    method public int describeContents();
-    method public boolean getIncludeTxPower();
-    method public int getInterval();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingParameters> CREATOR;
-  }
-
-  public static final class PeriodicAdvertisingParameters.Builder {
-    ctor public PeriodicAdvertisingParameters.Builder();
-    method public android.bluetooth.le.PeriodicAdvertisingParameters build();
-    method public android.bluetooth.le.PeriodicAdvertisingParameters.Builder setIncludeTxPower(boolean);
-    method public android.bluetooth.le.PeriodicAdvertisingParameters.Builder setInterval(int);
-  }
-
-  public abstract class ScanCallback {
-    ctor public ScanCallback();
-    method public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult>);
-    method public void onScanFailed(int);
-    method public void onScanResult(int, android.bluetooth.le.ScanResult);
-    field public static final int SCAN_FAILED_ALREADY_STARTED = 1; // 0x1
-    field public static final int SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2; // 0x2
-    field public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4; // 0x4
-    field public static final int SCAN_FAILED_INTERNAL_ERROR = 3; // 0x3
-  }
-
-  public final class ScanFilter implements android.os.Parcelable {
-    method public int describeContents();
-    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 @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 @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanFilter> CREATOR;
-  }
-
-  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(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[]);
-    method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[], byte[]);
-    method @NonNull public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(@Nullable android.os.ParcelUuid);
-    method @NonNull public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(@Nullable android.os.ParcelUuid, @Nullable android.os.ParcelUuid);
-    method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid);
-    method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
-  }
-
-  public final class ScanRecord {
-    method public int getAdvertiseFlags();
-    method public byte[] getBytes();
-    method @Nullable public String getDeviceName();
-    method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
-    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 @NonNull 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 @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();
-    method public int getDataStatus();
-    method public android.bluetooth.BluetoothDevice getDevice();
-    method public int getPeriodicAdvertisingInterval();
-    method public int getPrimaryPhy();
-    method public int getRssi();
-    method @Nullable public android.bluetooth.le.ScanRecord getScanRecord();
-    method public int getSecondaryPhy();
-    method public long getTimestampNanos();
-    method public int getTxPower();
-    method public boolean isConnectable();
-    method public boolean isLegacy();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
-    field public static final int DATA_COMPLETE = 0; // 0x0
-    field public static final int DATA_TRUNCATED = 2; // 0x2
-    field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
-    field public static final int PHY_UNUSED = 0; // 0x0
-    field public static final int SID_NOT_PRESENT = 255; // 0xff
-    field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
-  }
-
-  public final class ScanSettings implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getCallbackType();
-    method public boolean getLegacy();
-    method public int getPhy();
-    method public long getReportDelayMillis();
-    method public int getScanMode();
-    method public int getScanResultType();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int CALLBACK_TYPE_ALL_MATCHES = 1; // 0x1
-    field public static final int CALLBACK_TYPE_FIRST_MATCH = 2; // 0x2
-    field public static final int CALLBACK_TYPE_MATCH_LOST = 4; // 0x4
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanSettings> CREATOR;
-    field public static final int MATCH_MODE_AGGRESSIVE = 1; // 0x1
-    field public static final int MATCH_MODE_STICKY = 2; // 0x2
-    field public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; // 0x2
-    field public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; // 0x3
-    field public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; // 0x1
-    field public static final int PHY_LE_ALL_SUPPORTED = 255; // 0xff
-    field public static final int SCAN_MODE_BALANCED = 1; // 0x1
-    field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
-    field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
-    field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
-  }
-
-  public static final class ScanSettings.Builder {
-    ctor public ScanSettings.Builder();
-    method public android.bluetooth.le.ScanSettings build();
-    method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
-    method public android.bluetooth.le.ScanSettings.Builder setLegacy(boolean);
-    method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
-    method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
-    method public android.bluetooth.le.ScanSettings.Builder setPhy(int);
-    method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
-    method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
-  }
-
-  public final class TransportBlock implements android.os.Parcelable {
-    ctor public TransportBlock(int, int, int, @Nullable byte[]);
-    method public int describeContents();
-    method public int getOrgId();
-    method public int getTdsFlags();
-    method @Nullable public byte[] getTransportData();
-    method public int getTransportDataLength();
-    method @Nullable public byte[] toByteArray();
-    method public int totalBytes();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.TransportBlock> CREATOR;
-  }
-
-  public final class TransportDiscoveryData implements android.os.Parcelable {
-    ctor public TransportDiscoveryData(int, @NonNull java.util.List<android.bluetooth.le.TransportBlock>);
-    ctor public TransportDiscoveryData(@NonNull byte[]);
-    method public int describeContents();
-    method @NonNull public java.util.List<android.bluetooth.le.TransportBlock> getTransportBlocks();
-    method public int getTransportDataType();
-    method @Nullable public byte[] toByteArray();
-    method public int totalBytes();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.TransportDiscoveryData> CREATOR;
-  }
-
-}
-
 package android.companion {
 
   public final class AssociationInfo implements android.os.Parcelable {
@@ -13545,6 +12216,7 @@
   }
 
   public final class ShortcutInfo implements android.os.Parcelable {
+    method @NonNull public static android.content.pm.ShortcutInfo createFromGenericDocument(@NonNull android.content.Context, @NonNull android.app.appsearch.GenericDocument);
     method public int describeContents();
     method @Nullable public android.content.ComponentName getActivity();
     method @NonNull public java.util.List<java.lang.String> getCapabilityParameterValues(@NonNull String, @NonNull String);
@@ -19900,7 +18572,6 @@
   public abstract class AbstractInputMethodService extends android.app.Service implements android.view.KeyEvent.Callback {
     ctor public AbstractInputMethodService();
     method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
-    method public final boolean isUiContext();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
     method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
@@ -22585,12 +21256,14 @@
     field @Deprecated public static final int COLOR_FormatYUV422SemiPlanar = 24; // 0x18
     field public static final int COLOR_FormatYUV444Flexible = 2135181448; // 0x7f444888
     field @Deprecated public static final int COLOR_FormatYUV444Interleaved = 29; // 0x1d
+    field public static final int COLOR_FormatYUVP010 = 54; // 0x36
     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_EncodingStatistics = "encoding-statistics";
     field public static final String FEATURE_FrameParsing = "frame-parsing";
+    field public static final String FEATURE_HdrEditing = "hdr-editing";
     field public static final String FEATURE_IntraRefresh = "intra-refresh";
     field public static final String FEATURE_LowLatency = "low-latency";
     field public static final String FEATURE_MultipleFrames = "multiple-frames";
@@ -24544,6 +23217,7 @@
     method public static android.net.Uri getValidRingtoneUri(android.content.Context);
     method public boolean hasHapticChannels(int);
     method public static boolean hasHapticChannels(@NonNull android.net.Uri);
+    method public static boolean hasHapticChannels(@NonNull android.content.Context, @NonNull android.net.Uri);
     method public int inferStreamType();
     method public static boolean isDefault(android.net.Uri);
     method @Nullable public static android.content.res.AssetFileDescriptor openDefaultRingtoneUri(@NonNull android.content.Context, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
@@ -26219,6 +24893,37 @@
 
 package android.media.tv {
 
+  public final class AdRequest implements android.os.Parcelable {
+    ctor public AdRequest(int, int, @Nullable android.os.ParcelFileDescriptor, long, long, long, @Nullable String, @NonNull android.os.Bundle);
+    method public int describeContents();
+    method public long getEchoIntervalMillis();
+    method @Nullable public android.os.ParcelFileDescriptor getFileDescriptor();
+    method public int getId();
+    method @Nullable public String getMediaFileType();
+    method @NonNull public android.os.Bundle getMetadata();
+    method public int getRequestType();
+    method public long getStartTimeMillis();
+    method public long getStopTimeMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.AdRequest> CREATOR;
+    field public static final int REQUEST_TYPE_START = 1; // 0x1
+    field public static final int REQUEST_TYPE_STOP = 2; // 0x2
+  }
+
+  public final class AdResponse implements android.os.Parcelable {
+    ctor public AdResponse(int, int, long);
+    method public int describeContents();
+    method public long getElapsedTimeMillis();
+    method public int getId();
+    method public int getResponseType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.AdResponse> CREATOR;
+    field public static final int RESPONSE_TYPE_ERROR = 4; // 0x4
+    field public static final int RESPONSE_TYPE_FINISHED = 2; // 0x2
+    field public static final int RESPONSE_TYPE_PLAYING = 1; // 0x1
+    field public static final int RESPONSE_TYPE_STOPPED = 3; // 0x3
+  }
+
   public final class AitInfo implements android.os.Parcelable {
     ctor public AitInfo(int, int);
     method public int describeContents();
@@ -26721,6 +25426,9 @@
     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
+    field public static final int SIGNAL_STRENGTH_LOST = 1; // 0x1
+    field public static final int SIGNAL_STRENGTH_STRONG = 3; // 0x3
+    field public static final int SIGNAL_STRENGTH_WEAK = 2; // 0x2
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
     field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
@@ -26798,10 +25506,12 @@
   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 notifyAdResponse(@NonNull android.media.tv.AdResponse);
     method public void notifyAitInfoUpdated(@NonNull android.media.tv.AitInfo);
     method public void notifyChannelRetuned(android.net.Uri);
     method public void notifyContentAllowed();
     method public void notifyContentBlocked(@NonNull android.media.tv.TvContentRating);
+    method public void notifySignalStrength(int);
     method public void notifyTimeShiftStatusChanged(int);
     method public void notifyTrackSelected(int, String);
     method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
@@ -26817,6 +25527,7 @@
     method public boolean onKeyUp(int, android.view.KeyEvent);
     method public void onOverlayViewSizeChanged(int, int);
     method public abstract void onRelease();
+    method public void onRequestAd(@NonNull android.media.tv.AdRequest);
     method public boolean onSelectTrack(int, @Nullable String);
     method public abstract void onSetCaptionEnabled(boolean);
     method public void onSetInteractiveAppNotificationEnabled(boolean);
@@ -26954,9 +25665,11 @@
     method public void onContentAllowed(String);
     method public void onContentBlocked(String, android.media.tv.TvContentRating);
     method public void onDisconnected(String);
+    method public void onSignalStrength(@NonNull String, int);
     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 onTuned(@NonNull String, @NonNull android.net.Uri);
     method public void onVideoAvailable(String);
     method public void onVideoSizeChanged(String, int, int);
     method public void onVideoUnavailable(String, int);
@@ -26981,8 +25694,11 @@
 
   public final class TvInteractiveAppManager {
     method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppInfo> getTvInteractiveAppServiceList();
+    method public void prepare(@NonNull String, int);
     method public void registerCallback(@NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback, @NonNull java.util.concurrent.Executor);
+    method public void sendAppLinkCommand(@NonNull String, @NonNull android.os.Bundle);
     method public void unregisterCallback(@NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
+    field public static final String ACTION_APP_LINK_COMMAND = "android.media.tv.interactive.action.APP_LINK_COMMAND";
     field public static final int ERROR_BLOCKED = 5; // 0x5
     field public static final int ERROR_ENCRYPTED = 6; // 0x6
     field public static final int ERROR_NONE = 0; // 0x0
@@ -26991,26 +25707,55 @@
     field public static final int ERROR_UNKNOWN = 1; // 0x1
     field public static final int ERROR_UNKNOWN_CHANNEL = 7; // 0x7
     field public static final int ERROR_WEAK_SIGNAL = 3; // 0x3
+    field public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
+    field public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
+    field public static final String INTENT_KEY_CHANNEL_URI = "channel_uri";
+    field public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
+    field public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id";
     field public static final int INTERACTIVE_APP_STATE_ERROR = 3; // 0x3
     field public static final int INTERACTIVE_APP_STATE_RUNNING = 2; // 0x2
     field public static final int INTERACTIVE_APP_STATE_STOPPED = 1; // 0x1
+    field public static final String KEY_BACK_URI = "back_uri";
+    field public static final String KEY_CLASS_NAME = "class_name";
+    field public static final String KEY_COMMAND_TYPE = "command_type";
+    field public static final String KEY_PACKAGE_NAME = "package_name";
+    field public static final String KEY_SERVICE_ID = "service_id";
     field public static final int SERVICE_STATE_ERROR = 4; // 0x4
     field public static final int SERVICE_STATE_PREPARING = 2; // 0x2
     field public static final int SERVICE_STATE_READY = 3; // 0x3
     field public static final int SERVICE_STATE_UNREALIZED = 1; // 0x1
+    field public static final int TELETEXT_APP_STATE_ERROR = 3; // 0x3
+    field public static final int TELETEXT_APP_STATE_HIDE = 2; // 0x2
+    field public static final int TELETEXT_APP_STATE_SHOW = 1; // 0x1
   }
 
   public abstract static class TvInteractiveAppManager.TvInteractiveAppCallback {
     ctor public TvInteractiveAppManager.TvInteractiveAppCallback();
+    method public void onInteractiveAppServiceAdded(@NonNull String);
+    method public void onInteractiveAppServiceRemoved(@NonNull String);
+    method public void onInteractiveAppServiceUpdated(@NonNull String);
     method public void onTvInteractiveAppServiceStateChanged(@NonNull String, int, int, int);
   }
 
   public abstract class TvInteractiveAppService extends android.app.Service {
     ctor public TvInteractiveAppService();
     method public final void notifyStateChanged(int, int, int);
-    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onAppLinkCommand(@NonNull android.os.Bundle);
+    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method @Nullable public abstract android.media.tv.interactive.TvInteractiveAppService.Session onCreateSession(@NonNull String, int);
     method public abstract void onPrepare(int);
+    field public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly";
+    field public static final String COMMAND_PARAMETER_KEY_CHANNEL_URI = "command_channel_uri";
+    field public static final String COMMAND_PARAMETER_KEY_INPUT_ID = "command_input_id";
+    field public static final String COMMAND_PARAMETER_KEY_TRACK_ID = "command_track_id";
+    field public static final String COMMAND_PARAMETER_KEY_TRACK_TYPE = "command_track_type";
+    field public static final String COMMAND_PARAMETER_KEY_VOLUME = "command_volume";
+    field public static final String PLAYBACK_COMMAND_TYPE_SELECT_TRACK = "select_track";
+    field public static final String PLAYBACK_COMMAND_TYPE_SET_STREAM_VOLUME = "set_stream_volume";
+    field public static final String PLAYBACK_COMMAND_TYPE_STOP = "stop";
+    field public static final String PLAYBACK_COMMAND_TYPE_TUNE = "tune";
+    field public static final String PLAYBACK_COMMAND_TYPE_TUNE_NEXT = "tune_next";
+    field public static final String PLAYBACK_COMMAND_TYPE_TUNE_PREV = "tune_previous";
     field public static final String SERVICE_INTERFACE = "android.media.tv.interactive.TvInteractiveAppService";
     field public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
   }
@@ -27020,17 +25765,48 @@
     method public void layoutSurface(int, int, int, int);
     method public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
     method public void notifySessionStateChanged(int, int);
+    method public final void notifyTeletextAppStateChanged(int);
+    method public void onAdResponse(@NonNull android.media.tv.AdResponse);
+    method public void onContentAllowed();
+    method public void onContentBlocked(@NonNull android.media.tv.TvContentRating);
     method public void onCreateBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+    method @Nullable public android.view.View onCreateMediaView();
+    method public void onCurrentChannelLcn(int);
+    method public void onCurrentChannelUri(@Nullable android.net.Uri);
+    method public void onCurrentTvInputId(@Nullable String);
     method public void onDestroyBiInteractiveApp(@NonNull String);
+    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 onKeyUp(int, @NonNull android.view.KeyEvent);
+    method public void onMediaViewSizeChanged(int, int);
+    method public abstract void onRelease();
+    method public void onResetInteractiveApp();
     method public abstract boolean onSetSurface(@Nullable android.view.Surface);
+    method public void onSetTeletextAppEnabled(boolean);
+    method public void onSignalStrength(int);
     method public void onStartInteractiveApp();
     method public void onStopInteractiveApp();
+    method public void onStreamVolume(float);
     method public void onSurfaceChanged(int, int, int);
+    method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
+    method public void onTrackInfoList(@NonNull java.util.List<android.media.tv.TvTrackInfo>);
+    method public void onTrackSelected(int, @NonNull String);
+    method public boolean onTrackballEvent(@NonNull android.view.MotionEvent);
+    method public void onTracksChanged(@NonNull java.util.List<android.media.tv.TvTrackInfo>);
     method public void onTuned(@NonNull android.net.Uri);
+    method public void onVideoAvailable();
+    method public void onVideoUnavailable(int);
+    method public void requestAd(@NonNull android.media.tv.AdRequest);
+    method public void requestCurrentChannelLcn();
+    method public void requestCurrentChannelUri();
+    method public void requestCurrentTvInputId();
+    method public void requestStreamVolume();
+    method public void requestTrackInfoList();
+    method public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
+    method public void setMediaViewEnabled(boolean);
+    method public void setVideoBounds(@NonNull android.graphics.Rect);
   }
 
   public class TvInteractiveAppView extends android.view.ViewGroup {
@@ -27038,19 +25814,48 @@
     ctor public TvInteractiveAppView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
     ctor public TvInteractiveAppView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int);
     method public void clearCallback();
+    method public void clearOnUnhandledInputEventListener();
     method public void createBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
     method public void destroyBiInteractiveApp(@NonNull String);
+    method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void onLayout(boolean, int, int, int, int);
+    method public void onMeasure(int, int);
+    method public boolean onUnhandledInputEvent(@NonNull android.view.InputEvent);
+    method public void onVisibilityChanged(@NonNull android.view.View, int);
     method public void prepareInteractiveApp(@NonNull String, int);
+    method public void reset();
+    method public void resetInteractiveApp();
+    method public void sendCurrentChannelLcn(int);
+    method public void sendCurrentChannelUri(@Nullable android.net.Uri);
+    method public void sendCurrentTvInputId(@Nullable String);
+    method public void sendStreamVolume(float);
+    method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>);
     method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback);
+    method public void setOnUnhandledInputEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener);
+    method public void setTeletextAppEnabled(boolean);
     method public int setTvView(@Nullable android.media.tv.TvView);
     method public void startInteractiveApp();
     method public void stopInteractiveApp();
   }
 
+  public static interface TvInteractiveAppView.OnUnhandledInputEventListener {
+    method public boolean onUnhandledInputEvent(@NonNull android.view.InputEvent);
+  }
+
   public abstract static class TvInteractiveAppView.TvInteractiveAppCallback {
     ctor public TvInteractiveAppView.TvInteractiveAppCallback();
     method public void onBiInteractiveAppCreated(@NonNull String, @NonNull android.net.Uri, @Nullable String);
+    method public void onPlaybackCommandRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle);
+    method public void onRequestCurrentChannelLcn(@NonNull String);
+    method public void onRequestCurrentChannelUri(@NonNull String);
+    method public void onRequestCurrentTvInputId(@NonNull String);
+    method public void onRequestStreamVolume(@NonNull String);
+    method public void onRequestTrackInfoList(@NonNull String);
+    method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
     method public void onStateChanged(@NonNull String, int, int);
+    method public void onTeletextAppStateChanged(@NonNull String, int);
   }
 
 }
@@ -31615,6 +30420,7 @@
     field public static final int BATTERY_HEALTH_UNKNOWN = 1; // 0x1
     field public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; // 0x6
     field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
+    field public static final int BATTERY_PLUGGED_DOCK = 8; // 0x8
     field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
     field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
     field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
@@ -33122,6 +31928,9 @@
     method public static android.os.VibrationEffect createWaveform(long[], int[], int);
     method public int describeContents();
     method @NonNull public static android.os.VibrationEffect.Composition startComposition();
+    method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform();
+    method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform(@NonNull android.os.VibrationEffect.VibrationParameter);
+    method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform(@NonNull android.os.VibrationEffect.VibrationParameter, @NonNull android.os.VibrationEffect.VibrationParameter);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR;
     field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff
     field public static final int EFFECT_CLICK = 0; // 0x0
@@ -33131,10 +31940,13 @@
   }
 
   public static final class VibrationEffect.Composition {
+    method @NonNull public android.os.VibrationEffect.Composition addEffect(@NonNull android.os.VibrationEffect);
+    method @NonNull public android.os.VibrationEffect.Composition addOffDuration(@NonNull java.time.Duration);
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int);
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float);
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
     method @NonNull public android.os.VibrationEffect compose();
+    method @NonNull public android.os.VibrationEffect.Composition repeatEffectIndefinitely(@NonNull android.os.VibrationEffect);
     field public static final int PRIMITIVE_CLICK = 1; // 0x1
     field public static final int PRIMITIVE_LOW_TICK = 8; // 0x8
     field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6
@@ -33145,6 +31957,21 @@
     field public static final int PRIMITIVE_TICK = 7; // 0x7
   }
 
+  public static final class VibrationEffect.Composition.UnreachableAfterRepeatingIndefinitelyException extends java.lang.IllegalStateException {
+  }
+
+  public static class VibrationEffect.VibrationParameter {
+    method @NonNull public static android.os.VibrationEffect.VibrationParameter targetAmplitude(@FloatRange(from=0, to=1) float);
+    method @NonNull public static android.os.VibrationEffect.VibrationParameter targetFrequency(@FloatRange(from=1) float);
+  }
+
+  public static final class VibrationEffect.WaveformBuilder {
+    method @NonNull public android.os.VibrationEffect.WaveformBuilder addSustain(@NonNull java.time.Duration);
+    method @NonNull public android.os.VibrationEffect.WaveformBuilder addTransition(@NonNull java.time.Duration, @NonNull android.os.VibrationEffect.VibrationParameter);
+    method @NonNull public android.os.VibrationEffect.WaveformBuilder addTransition(@NonNull java.time.Duration, @NonNull android.os.VibrationEffect.VibrationParameter, @NonNull android.os.VibrationEffect.VibrationParameter);
+    method @NonNull public android.os.VibrationEffect build();
+  }
+
   public abstract class Vibrator {
     method public final int areAllEffectsSupported(@NonNull int...);
     method public final boolean areAllPrimitivesSupported(@NonNull int...);
@@ -41374,8 +40201,10 @@
     field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
+    field public static final int CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS = 65536; // 0x10000
     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 int CAPABILITY_VOICE_CALLING_AVAILABLE = 131072; // 0x20000
     field @NonNull public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final String EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE = "android.telecom.extra.ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE";
     field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
@@ -42315,6 +41144,7 @@
     field public static final String KEY_SIP_TIMER_T1_MILLIS_INT = "ims.sip_timer_t1_millis_int";
     field public static final String KEY_SIP_TIMER_T2_MILLIS_INT = "ims.sip_timer_t2_millis_int";
     field public static final String KEY_SIP_TIMER_T4_MILLIS_INT = "ims.sip_timer_t4_millis_int";
+    field public static final String KEY_SUPPORTED_RATS_INT_ARRAY = "ims.supported_rats_int_array";
     field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
     field public static final int NETWORK_TYPE_HOME = 0; // 0x0
     field public static final int NETWORK_TYPE_ROAMING = 1; // 0x1
@@ -42335,6 +41165,7 @@
     field public static final String KEY_EMERGENCY_QOS_PRECONDITION_SUPPORTED_BOOL = "imsemergency.emergency_qos_precondition_supported_bool";
     field public static final String KEY_EMERGENCY_REGISTRATION_TIMER_MILLIS_INT = "imsemergency.emergency_registration_timer_millis_int";
     field public static final String KEY_PREFIX = "imsemergency.";
+    field public static final String KEY_REFRESH_GEOLOCATION_TIMEOUT_MILLIS_INT = "imsemergency.refresh_geolocation_timeout_millis_int";
     field public static final String KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL = "imsemergency.retry_emergency_on_ims_pdn_bool";
   }
 
@@ -42344,7 +41175,6 @@
     field public static final String KEY_T140_PAYLOAD_TYPE_INT = "imsrtt.t140_payload_type_int";
     field public static final String KEY_TEXT_AS_BANDWIDTH_KBPS_INT = "imsrtt.text_as_bandwidth_kbps_int";
     field public static final String KEY_TEXT_CODEC_CAPABILITY_PAYLOAD_TYPES_BUNDLE = "imsrtt.text_codec_capability_payload_types_bundle";
-    field public static final String KEY_TEXT_INACTIVITY_CALL_END_REASONS_INT_ARRAY = "imsrtt.text_inactivity_call_end_reasons_int_array";
     field public static final String KEY_TEXT_ON_DEFAULT_BEARER_SUPPORTED_BOOL = "imsrtt.text_on_default_bearer_supported_bool";
     field public static final String KEY_TEXT_QOS_PRECONDITION_SUPPORTED_BOOL = "imsrtt.text_qos_precondition_supported_bool";
     field public static final String KEY_TEXT_RR_BANDWIDTH_BPS_INT = "imsrtt.text_rr_bandwidth_bps_int";
@@ -42380,6 +41210,7 @@
     field public static final String KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL = "imsss.ut_requires_ims_registration_bool";
     field public static final String KEY_UT_SERVER_BASED_SERVICES_INT_ARRAY = "imsss.ut_server_based_services_int_array";
     field public static final String KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL = "imsss.ut_supported_when_ps_data_off_bool";
+    field public static final String KEY_UT_SUPPORTED_WHEN_ROAMING_BOOL = "imsss.ut_supported_when_roaming_bool";
     field public static final String KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY = "imsss.ut_terminal_based_services_int_array";
     field public static final String KEY_UT_TRANSPORT_TYPE_INT = "imsss.ut_transport_type_int";
     field public static final String KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY = "imsss.xcap_over_ut_supported_rats_int_array";
@@ -42479,6 +41310,7 @@
     field public static final String KEY_RINGBACK_TIMER_MILLIS_INT = "imsvoice.ringback_timer_millis_int";
     field public static final String KEY_RINGING_TIMER_MILLIS_INT = "imsvoice.ringing_timer_millis_int";
     field public static final String KEY_SESSION_EXPIRES_TIMER_SEC_INT = "imsvoice.session_expires_timer_sec_int";
+    field public static final String KEY_SESSION_PRIVACY_TYPE_INT = "imsvoice.session_privacy_type_int";
     field public static final String KEY_SESSION_REFRESHER_TYPE_INT = "imsvoice.session_refresher_type_int";
     field public static final String KEY_SESSION_REFRESH_METHOD_INT = "imsvoice.session_refresh_method_int";
     field public static final String KEY_SESSION_TIMER_SUPPORTED_BOOL = "imsvoice.session_timer_supported_bool";
@@ -42488,6 +41320,9 @@
     field public static final int MIDCALL_SRVCC_SUPPORT = 3; // 0x3
     field public static final int OCTET_ALIGNED = 1; // 0x1
     field public static final int PREALERTING_SRVCC_SUPPORT = 2; // 0x2
+    field public static final int SESSION_PRIVACY_TYPE_HEADER = 0; // 0x0
+    field public static final int SESSION_PRIVACY_TYPE_ID = 2; // 0x2
+    field public static final int SESSION_PRIVACY_TYPE_NONE = 1; // 0x1
     field public static final int SESSION_REFRESHER_TYPE_UAC = 1; // 0x1
     field public static final int SESSION_REFRESHER_TYPE_UAS = 2; // 0x2
     field public static final int SESSION_REFRESHER_TYPE_UNKNOWN = 0; // 0x0
@@ -48489,6 +47324,7 @@
     method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
     method public default int getBufferTransformHint();
     method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
+    method public default void setTouchableRegion(@Nullable android.graphics.Region);
   }
 
   @UiThread public static interface AttachedSurfaceControl.OnBufferTransformHintChangedListener {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index ee31e13..6c2db43 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -63,8 +63,8 @@
 
   public class DevicePolicyManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void acknowledgeNewUserDisclaimer();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearLogoutUser();
-    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getLogoutUser();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getLogoutUser();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int logoutUser();
     field public static final String ACTION_SHOW_NEW_USER_DISCLAIMER = "android.app.action.SHOW_NEW_USER_DISCLAIMER";
   }
 
@@ -93,20 +93,6 @@
 
 }
 
-package android.bluetooth {
-
-  public class BluetoothFrameworkInitializer {
-    method public static void registerServiceWrappers();
-    method public static void setBinderCallsStatsInitializer(@NonNull java.util.function.Consumer<android.content.Context>);
-    method public static void setBluetoothServiceManager(@NonNull android.os.BluetoothServiceManager);
-  }
-
-  public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
-    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.TETHER_PRIVILEGED}) public android.net.TetheringManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheredInterfaceCallback);
-  }
-
-}
-
 package android.content {
 
   public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
@@ -384,6 +370,7 @@
     method public int getRoaming();
     method @NonNull public java.util.Set<java.lang.String> getSubscriberIds();
     method @NonNull public java.util.Set<java.lang.String> getWifiNetworkKeys();
+    method public boolean matches(@NonNull android.net.NetworkIdentity);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkTemplate> CREATOR;
     field public static final int MATCH_BLUETOOTH = 8; // 0x8
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ea2a641..55a6df2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -744,6 +744,7 @@
     method public void clearRequireCompatChange();
     method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
     method public static android.app.BroadcastOptions makeBasic();
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void recordResponseEventWhileInBackground(@IntRange(from=0) long);
     method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
     method public void setDontSendToRestrictedApps(boolean);
     method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
@@ -2257,475 +2258,6 @@
 
 }
 
-package android.bluetooth {
-
-  public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
-    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BufferConstraints getBufferConstraints();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getDynamicBufferSupport();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setBufferLengthMillis(int, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
-    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
-    field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
-    field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0
-    field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0
-    field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1
-    field public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; // 0xffffffff
-    field public static final int OPTIONAL_CODECS_SUPPORTED = 1; // 0x1
-    field public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; // 0xffffffff
-  }
-
-  public final class BluetoothA2dpSink implements android.bluetooth.BluetoothProfile {
-    method public void finalize();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothActivityEnergyInfo implements android.os.Parcelable {
-    method public int getBluetoothStackState();
-    method public long getControllerEnergyUsed();
-    method public long getControllerIdleTimeMillis();
-    method public long getControllerRxTimeMillis();
-    method public long getControllerTxTimeMillis();
-    method public long getTimestampMillis();
-    method @NonNull public java.util.List<android.bluetooth.UidTraffic> getUidTraffic();
-    method public boolean isValid();
-    field public static final int BT_STACK_STATE_INVALID = 0; // 0x0
-    field public static final int BT_STACK_STATE_STATE_ACTIVE = 1; // 0x1
-    field public static final int BT_STACK_STATE_STATE_IDLE = 3; // 0x3
-    field public static final int BT_STACK_STATE_STATE_SCANNING = 2; // 0x2
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothActivityEnergyInfo> CREATOR;
-  }
-
-  public final class BluetoothAdapter {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean disable(boolean);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableNoAutoConnect();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback);
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getActiveDevices(int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public long getDiscoveryEndMillis();
-    method public boolean isBleScanAlwaysAvailable();
-    method public boolean isLeEnabled();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean removeActiveDevice(int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setDiscoverableTimeout(@NonNull java.time.Duration);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int setScanMode(int);
-    field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
-    field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
-    field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
-    field public static final int ACTIVE_DEVICE_AUDIO = 0; // 0x0
-    field public static final int ACTIVE_DEVICE_PHONE_CALL = 1; // 0x1
-  }
-
-  public static interface BluetoothAdapter.OnMetadataChangedListener {
-    method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
-  }
-
-  public static interface BluetoothAdapter.OobDataCallback {
-    method public void onError(int);
-    method public void onOobData(int, @NonNull android.bluetooth.OobData);
-  }
-
-  public final class BluetoothClass implements android.os.Parcelable {
-    field public static final int PROFILE_A2DP_SINK = 6; // 0x6
-    field public static final int PROFILE_NAP = 5; // 0x5
-    field public static final int PROFILE_OPP = 2; // 0x2
-    field public static final int PROFILE_PANU = 4; // 0x4
-  }
-
-  public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<java.lang.Integer> getAllGroupIds(@Nullable android.os.ParcelUuid);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.Map getGroupUuidMapByDevice(@Nullable android.bluetooth.BluetoothDevice);
-    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.UUID groupLock(int, @Nullable java.util.concurrent.Executor, @Nullable android.bluetooth.BluetoothCsipSetCoordinator.ClientLockCallback);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean groupUnlock(@NonNull java.util.UUID);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CSIS_DEVICE_AVAILABLE = "android.bluetooth.action.CSIS_DEVICE_AVAILABLE";
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE = "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE";
-  }
-
-  public static interface BluetoothCsipSetCoordinator.ClientLockCallback {
-    method public void onGroupLockSet(int, int, boolean);
-  }
-
-  public final class BluetoothDevice implements android.os.Parcelable {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean canBondWithoutDialog();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean cancelBondProcess();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public int connect();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBond(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int disconnect();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean fetchUuidsWithSdp(int);
-    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public byte[] getMetadata(int);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getSimAccessPermission();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isConnected();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isEncrypted();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInSilenceMode();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setLowLatencyAudioAllowed(boolean);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMessageAccessPermission(int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setMetadata(int, @NonNull byte[]);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setPhonebookAccessPermission(int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setSilenceMode(boolean);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setSimAccessPermission(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 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
-    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_SWITCH_BUFFER_SIZE = "android.bluetooth.device.action.SWITCH_BUFFER_SIZE";
-    field public static final String DEVICE_TYPE_DEFAULT = "Default";
-    field public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
-    field public static final String DEVICE_TYPE_WATCH = "Watch";
-    field public static final String EXTRA_LOW_LATENCY_BUFFER_SIZE = "android.bluetooth.device.extra.LOW_LATENCY_BUFFER_SIZE";
-    field public static final int METADATA_COMPANION_APP = 4; // 0x4
-    field public static final int METADATA_DEVICE_TYPE = 17; // 0x11
-    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_UNTETHERED_HEADSET = 6; // 0x6
-    field public static final int METADATA_MAIN_BATTERY = 18; // 0x12
-    field public static final int METADATA_MAIN_CHARGING = 19; // 0x13
-    field public static final int METADATA_MAIN_ICON = 5; // 0x5
-    field public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; // 0x14
-    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_UNTETHERED_CASE_BATTERY = 12; // 0xc
-    field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
-    field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
-    field public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; // 0x17
-    field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
-    field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
-    field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
-    field public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; // 0x15
-    field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
-    field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
-    field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
-    field public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; // 0x16
-  }
-
-  public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int connectAudio();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int disconnectAudio();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioState(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInbandRingingEnabled();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startScoUsingVirtualVoiceCall();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean stopScoUsingVirtualVoiceCall();
-  }
-
-  public final class BluetoothHeadsetClient implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headsetprofile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public long getHiSyncId(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-  }
-
-  public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-  }
-
-  public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
-    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioLocation(@NonNull android.bluetooth.BluetoothDevice);
-  }
-
-  public final class BluetoothMap implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method public void close();
-    method protected void finalize();
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothMapClient implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.SEND_SMS}) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isTetheringOn();
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.TETHER_PRIVILEGED}) public void setBluetoothTethering(boolean);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
-    field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
-    field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
-    field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
-    field public static final int LOCAL_NAP_ROLE = 1; // 0x1
-    field public static final int LOCAL_PANU_ROLE = 2; // 0x2
-    field public static final int PAN_ROLE_NONE = 0; // 0x0
-    field public static final int REMOTE_NAP_ROLE = 1; // 0x1
-    field public static final int REMOTE_PANU_ROLE = 2; // 0x2
-    field public static final int TETHERING_STATE_OFF = 1; // 0x1
-    field public static final int TETHERING_STATE_ON = 2; // 0x2
-  }
-
-  public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BluetoothPbapClient implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public interface BluetoothProfile {
-    field public static final int A2DP_SINK = 11; // 0xb
-    field public static final int AVRCP_CONTROLLER = 12; // 0xc
-    field public static final int CONNECTION_POLICY_ALLOWED = 100; // 0x64
-    field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
-    field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
-    field public static final int HEADSET_CLIENT = 16; // 0x10
-    field public static final int MAP_CLIENT = 18; // 0x12
-    field public static final int PAN = 5; // 0x5
-    field public static final int PBAP_CLIENT = 17; // 0x11
-    field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
-    field @Deprecated public static final int PRIORITY_ON = 100; // 0x64
-    field public static final int VOLUME_CONTROL = 23; // 0x17
-  }
-
-  public final class BluetoothStatusCodes {
-    field public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000; // 0x3e8
-    field public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116; // 0x45c
-    field public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117; // 0x45d
-    field public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118; // 0x45e
-    field public static final int ERROR_CALL_ACTIVE = 1119; // 0x45f
-    field public static final int ERROR_NOT_ACTIVE_DEVICE = 12; // 0xc
-    field public static final int ERROR_NO_ACTIVE_DEVICES = 13; // 0xd
-    field public static final int ERROR_PROFILE_NOT_CONNECTED = 14; // 0xe
-    field public static final int ERROR_TIMEOUT = 15; // 0xf
-  }
-
-  public final class BluetoothUuid {
-    method public static boolean containsAnyUuid(@Nullable android.os.ParcelUuid[], @Nullable android.os.ParcelUuid[]);
-    method @NonNull public static android.os.ParcelUuid parseUuidFrom(@Nullable byte[]);
-    field @NonNull public static final android.os.ParcelUuid A2DP_SINK;
-    field @NonNull public static final android.os.ParcelUuid A2DP_SOURCE;
-    field @NonNull public static final android.os.ParcelUuid ADV_AUDIO_DIST;
-    field @NonNull public static final android.os.ParcelUuid AVRCP_CONTROLLER;
-    field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
-    field @NonNull public static final android.os.ParcelUuid BASE_UUID;
-    field @NonNull public static final android.os.ParcelUuid BNEP;
-    field @NonNull public static final android.os.ParcelUuid CAP;
-    field @NonNull public static final android.os.ParcelUuid COORDINATED_SET;
-    field @NonNull public static final android.os.ParcelUuid DIP;
-    field @NonNull public static final android.os.ParcelUuid GENERIC_MEDIA_CONTROL;
-    field @NonNull public static final android.os.ParcelUuid HAS;
-    field @NonNull public static final android.os.ParcelUuid HEARING_AID;
-    field @NonNull public static final android.os.ParcelUuid HFP;
-    field @NonNull public static final android.os.ParcelUuid HFP_AG;
-    field @NonNull public static final android.os.ParcelUuid HID;
-    field @NonNull public static final android.os.ParcelUuid HOGP;
-    field @NonNull public static final android.os.ParcelUuid HSP;
-    field @NonNull public static final android.os.ParcelUuid HSP_AG;
-    field @NonNull public static final android.os.ParcelUuid LE_AUDIO;
-    field @NonNull public static final android.os.ParcelUuid MAP;
-    field @NonNull public static final android.os.ParcelUuid MAS;
-    field @NonNull public static final android.os.ParcelUuid MEDIA_CONTROL;
-    field @NonNull public static final android.os.ParcelUuid MNS;
-    field @NonNull public static final android.os.ParcelUuid NAP;
-    field @NonNull public static final android.os.ParcelUuid OBEX_OBJECT_PUSH;
-    field @NonNull public static final android.os.ParcelUuid PANU;
-    field @NonNull public static final android.os.ParcelUuid PBAP_PCE;
-    field @NonNull public static final android.os.ParcelUuid PBAP_PSE;
-    field @NonNull public static final android.os.ParcelUuid SAP;
-    field public static final int UUID_BYTES_128_BIT = 16; // 0x10
-    field public static final int UUID_BYTES_16_BIT = 2; // 0x2
-    field public static final int UUID_BYTES_32_BIT = 4; // 0x4
-    field @NonNull public static final android.os.ParcelUuid VOLUME_CONTROL;
-  }
-
-  public final class BluetoothVolumeControl implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setVolume(@Nullable android.bluetooth.BluetoothDevice, @IntRange(from=0, to=255) int);
-    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED";
-  }
-
-  public final class BufferConstraint implements android.os.Parcelable {
-    ctor public BufferConstraint(int, int, int);
-    method public int describeContents();
-    method public int getDefaultMillis();
-    method public int getMaxMillis();
-    method public int getMinMillis();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraint> CREATOR;
-  }
-
-  public final class BufferConstraints implements android.os.Parcelable {
-    ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>);
-    method public int describeContents();
-    method @Nullable public android.bluetooth.BufferConstraint forCodec(int);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
-  }
-
-  public final class OobData implements android.os.Parcelable {
-    method @NonNull public byte[] getClassOfDevice();
-    method @NonNull public byte[] getClassicLength();
-    method @NonNull public byte[] getConfirmationHash();
-    method @NonNull public byte[] getDeviceAddressWithType();
-    method @Nullable public byte[] getDeviceName();
-    method @Nullable public byte[] getLeAppearance();
-    method @NonNull public int getLeDeviceRole();
-    method @NonNull public int getLeFlags();
-    method @Nullable public byte[] getLeTemporaryKey();
-    method @NonNull public byte[] getRandomizerHash();
-    field public static final int CLASS_OF_DEVICE_OCTETS = 3; // 0x3
-    field public static final int CONFIRMATION_OCTETS = 16; // 0x10
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-    field public static final int DEVICE_ADDRESS_OCTETS = 7; // 0x7
-    field public static final int LE_APPEARANCE_OCTETS = 2; // 0x2
-    field public static final int LE_DEVICE_FLAG_OCTETS = 1; // 0x1
-    field public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 3; // 0x3
-    field public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 2; // 0x2
-    field public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 1; // 0x1
-    field public static final int LE_DEVICE_ROLE_OCTETS = 1; // 0x1
-    field public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0; // 0x0
-    field public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 2; // 0x2
-    field public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 1; // 0x1
-    field public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0; // 0x0
-    field public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 3; // 0x3
-    field public static final int LE_FLAG_SIMULTANEOUS_HOST = 4; // 0x4
-    field public static final int LE_TK_OCTETS = 16; // 0x10
-    field public static final int OOB_LENGTH_OCTETS = 2; // 0x2
-    field public static final int RANDOMIZER_OCTETS = 16; // 0x10
-  }
-
-  public static final class OobData.ClassicBuilder {
-    ctor public OobData.ClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]);
-    method @NonNull public android.bluetooth.OobData build();
-    method @NonNull public android.bluetooth.OobData.ClassicBuilder setClassOfDevice(@NonNull byte[]);
-    method @NonNull public android.bluetooth.OobData.ClassicBuilder setDeviceName(@NonNull byte[]);
-    method @NonNull public android.bluetooth.OobData.ClassicBuilder setRandomizerHash(@NonNull byte[]);
-  }
-
-  public static final class OobData.LeBuilder {
-    ctor public OobData.LeBuilder(@NonNull byte[], @NonNull byte[], int);
-    method @NonNull public android.bluetooth.OobData build();
-    method @NonNull public android.bluetooth.OobData.LeBuilder setDeviceName(@NonNull byte[]);
-    method @NonNull public android.bluetooth.OobData.LeBuilder setLeFlags(int);
-    method @NonNull public android.bluetooth.OobData.LeBuilder setLeTemporaryKey(@NonNull byte[]);
-    method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]);
-  }
-
-  public final class UidTraffic implements java.lang.Cloneable android.os.Parcelable {
-    method public long getRxBytes();
-    method public long getTxBytes();
-    method public int getUid();
-    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.UidTraffic> CREATOR;
-  }
-
-}
-
-package android.bluetooth.le {
-
-  public final class AdvertiseSettings implements android.os.Parcelable {
-    method public int getOwnAddressType();
-  }
-
-  public static final class AdvertiseSettings.Builder {
-    method @NonNull public android.bluetooth.le.AdvertiseSettings.Builder setOwnAddressType(int);
-  }
-
-  public final class AdvertisingSetParameters implements android.os.Parcelable {
-    method public int getOwnAddressType();
-    field public static final int ADDRESS_TYPE_DEFAULT = -1; // 0xffffffff
-    field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
-    field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
-  }
-
-  public static final class AdvertisingSetParameters.Builder {
-    method @NonNull public android.bluetooth.le.AdvertisingSetParameters.Builder setOwnAddressType(int);
-  }
-
-  public final class BluetoothLeScanner {
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
-    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, 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 @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
-  }
-
-  @Deprecated public final class ResultStorageDescriptor implements android.os.Parcelable {
-    ctor @Deprecated public ResultStorageDescriptor(int, int, int);
-    method @Deprecated public int describeContents();
-    method @Deprecated public int getLength();
-    method @Deprecated public int getOffset();
-    method @Deprecated public int getType();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR;
-  }
-
-  public final class ScanFilter implements android.os.Parcelable {
-    method public int getAddressType();
-    method @Nullable public byte[] getIrk();
-  }
-
-  public static final class ScanFilter.Builder {
-    method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int);
-    method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int, @NonNull byte[]);
-    field public static final int LEN_IRK_OCTETS = 16; // 0x10
-  }
-
-  public final class ScanSettings implements android.os.Parcelable {
-    field public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; // 0x3
-    field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
-    field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0
-  }
-
-  public static final class ScanSettings.Builder {
-    method public android.bluetooth.le.ScanSettings.Builder setScanResultType(int);
-  }
-
-  @Deprecated public final class TruncatedFilter {
-    ctor @Deprecated public TruncatedFilter(android.bluetooth.le.ScanFilter, java.util.List<android.bluetooth.le.ResultStorageDescriptor>);
-    method @Deprecated public android.bluetooth.le.ScanFilter getFilter();
-    method @Deprecated public java.util.List<android.bluetooth.le.ResultStorageDescriptor> getStorageDescriptors();
-  }
-
-}
-
 package android.companion {
 
   public final class AssociationInfo implements android.os.Parcelable {
@@ -2768,12 +2300,26 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
   }
 
+  public static interface VirtualDeviceManager.ActivityListener {
+    method public void onDisplayEmpty(int);
+    method public void onTopActivityChanged(int, @NonNull android.content.ComponentName);
+  }
+
+  public static interface VirtualDeviceManager.LaunchCallback {
+    method public void onLaunchFailed();
+    method public void onLaunchSuccess();
+  }
+
   public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
+    method public void addActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
+    method public void addActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener, @NonNull java.util.concurrent.Executor);
     method public void close();
     method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(int, int, int, @Nullable android.view.Surface, int, @Nullable android.os.Handler, @Nullable android.hardware.display.VirtualDisplay.Callback);
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+    method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.LaunchCallback);
+    method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
   }
 
   public final class VirtualDeviceParams implements android.os.Parcelable {
@@ -5245,6 +4791,7 @@
     method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbData(boolean);
     method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int enableUsbDataWhileDocked();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
+    method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public int resetUsbPort();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
     field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1; // 0x1
     field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2; // 0x2
@@ -11184,6 +10731,7 @@
     method public void onCreate();
     method public void onDestroy();
     method public void onGameTaskFocusChanged(boolean);
+    method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public final boolean restartGame();
     method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
     method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
   }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 61c12dd..2303ddb 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -618,14 +618,6 @@
 
 }
 
-package android.bluetooth {
-
-  public final class BluetoothClass implements android.os.Parcelable {
-    method public int getClassOfDevice();
-  }
-
-}
-
 package android.companion {
 
   public abstract class CompanionDeviceService extends android.app.Service {
@@ -1802,7 +1794,6 @@
     method public static android.os.VibrationEffect get(int, boolean);
     method @Nullable public static android.os.VibrationEffect get(android.net.Uri, android.content.Context);
     method public abstract long getDuration();
-    method @NonNull public static android.os.VibrationEffect.WaveformBuilder startWaveform();
     field public static final int EFFECT_POP = 4; // 0x4
     field public static final int EFFECT_STRENGTH_LIGHT = 0; // 0x0
     field public static final int EFFECT_STRENGTH_MEDIUM = 1; // 0x1
@@ -1820,20 +1811,6 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Composed> CREATOR;
   }
 
-  public static final class VibrationEffect.Composition {
-    method @NonNull public android.os.VibrationEffect.Composition addEffect(@NonNull android.os.VibrationEffect);
-    method @NonNull public android.os.VibrationEffect.Composition addEffect(@NonNull android.os.VibrationEffect, @IntRange(from=0) int);
-  }
-
-  public static final class VibrationEffect.WaveformBuilder {
-    method @NonNull public android.os.VibrationEffect.WaveformBuilder addRamp(@FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
-    method @NonNull public android.os.VibrationEffect.WaveformBuilder addRamp(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=1.0f) float, @IntRange(from=0) int);
-    method @NonNull public android.os.VibrationEffect.WaveformBuilder addStep(@FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
-    method @NonNull public android.os.VibrationEffect.WaveformBuilder addStep(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=1.0f) float, @IntRange(from=0) int);
-    method @NonNull public android.os.VibrationEffect build();
-    method @NonNull public android.os.VibrationEffect build(int);
-  }
-
   public abstract class Vibrator {
     method public int getDefaultVibrationIntensity(int);
     field public static final int VIBRATION_INTENSITY_HIGH = 3; // 0x3
@@ -2508,6 +2485,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
     method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
+    method @RequiresPermission(android.Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE) public void setVoiceServiceStateOverride(boolean);
     field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
   }
 
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 7812aba..e31a566 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -52,6 +53,7 @@
     private String[] mRequireNoneOfPermissions;
     private long mRequireCompatChangeId = CHANGE_INVALID;
     private boolean mRequireCompatChangeEnabled = true;
+    private long mIdForResponseEvent;
 
     /**
      * Change ID which is invalid.
@@ -164,6 +166,12 @@
     public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED =
             PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
 
+    /**
+     * Corresponds to {@link #recordResponseEventWhileInBackground(long)}.
+     */
+    private static final String KEY_ID_FOR_RESPONSE_EVENT =
+            "android:broadcast.idForResponseEvent";
+
     public static BroadcastOptions makeBasic() {
         BroadcastOptions opts = new BroadcastOptions();
         return opts;
@@ -198,6 +206,7 @@
         mRequireNoneOfPermissions = opts.getStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS);
         mRequireCompatChangeId = opts.getLong(KEY_REQUIRE_COMPAT_CHANGE_ID, CHANGE_INVALID);
         mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true);
+        mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
     }
 
     /**
@@ -511,6 +520,28 @@
     }
 
     /**
+     * Sets whether events (such as posting a notification) originating from an app after it
+     * receives the broadcast while in background should be recorded as responses to the broadcast.
+     *
+     * @param id ID to be used for the response events corresponding to this broadcast. If the
+     *           value is {@code 0} (default), then response events will not be recorded. Otherwise,
+     *           they will be recorded with the ID provided.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+    public void recordResponseEventWhileInBackground(@IntRange(from = 0) long id) {
+        mIdForResponseEvent = id;
+    }
+
+    /** @hide */
+    @IntRange(from = 0)
+    public long getIdForResponseEvent() {
+        return mIdForResponseEvent;
+    }
+
+    /**
      * Returns the created options as a Bundle, which can be passed to
      * {@link android.content.Context#sendBroadcast(android.content.Intent)
      * Context.sendBroadcast(Intent)} and related methods.
@@ -549,6 +580,9 @@
             b.putLong(KEY_REQUIRE_COMPAT_CHANGE_ID, mRequireCompatChangeId);
             b.putBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, mRequireCompatChangeEnabled);
         }
+        if (mIdForResponseEvent != 0) {
+            b.putLong(KEY_ID_FOR_RESPONSE_EVENT, mIdForResponseEvent);
+        }
         return b.isEmpty() ? null : b;
     }
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 779552f1..d57c288 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6712,6 +6712,18 @@
             return;
         }
         boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
+
+        if (mSmallIcon != null
+                // Only bitmap icons can be downscaled.
+                && (mSmallIcon.getType() == Icon.TYPE_BITMAP
+                        || mSmallIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP)) {
+            Resources resources = context.getResources();
+            int maxSize = resources.getDimensionPixelSize(
+                    isLowRam ? R.dimen.notification_small_icon_size_low_ram
+                            : R.dimen.notification_small_icon_size);
+            mSmallIcon.scaleDownIfNecessary(maxSize, maxSize);
+        }
+
         if (mLargeIcon != null || largeIcon != null) {
             Resources resources = context.getResources();
             Class<? extends Style> style = getNotificationStyle();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4bdcf02..3960f4e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10091,12 +10091,29 @@
     }
 
     /**
+     * Same as {@link #logoutUser(ComponentName)}, but called by system (like Settings), not admin.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public @UserOperationResult int logoutUser() {
+        // TODO(b/214336184): add CTS test
+        try {
+            return mService.logoutUserInternal();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+    /**
      * Gets the user a {@link #logoutUser(ComponentName)} call would switch to,
      * or {@code null} if the current user is not in a session.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS})
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public @Nullable UserHandle getLogoutUser() {
         // TODO(b/214336184): add CTS test
@@ -10109,24 +10126,6 @@
     }
 
     /**
-     * Clears the user that {@link #logoutUser(ComponentName)} would switch to.
-     *
-     * <p>Typically used by system UI after it logout a session.
-     *
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public void clearLogoutUser() {
-        // TODO(b/214336184): add CTS test
-        try {
-            mService.clearLogoutUser();
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Called by a device owner to list all secondary users on the device. Managed profiles are not
      * considered as secondary users.
      * <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser}
@@ -10755,6 +10754,9 @@
      * On fully-managed devices this method is unsupported because all traffic is considered
      * work traffic.
      *
+     * <p> This method enables preferential network service with a default configuration.
+     * To fine-tune the configuration, use {@link #setPreferentialNetworkServiceConfig) instead.
+     *
      * <p>This method can only be called by the profile owner of a managed profile.
      * @param enabled whether preferential network service should be enabled.
      * @throws SecurityException if the caller is not the profile owner.
@@ -10793,6 +10795,56 @@
     }
 
     /**
+     * Sets preferential network configuration on the work profile.
+     * {@see PreferentialNetworkServiceConfig}
+     *
+     * An example of a supported preferential network service is the Enterprise
+     * slice on 5G networks.
+     *
+     * By default, preferential network service is disabled on the work profile on supported
+     * carriers and devices. Admins can explicitly enable it with this API.
+     * On fully-managed devices this method is unsupported because all traffic is considered
+     * work traffic.
+     *
+     * <p>This method can only be called by the profile owner of a managed profile.
+     * @param preferentialNetworkServiceConfig preferential network configuration.
+     * @throws SecurityException if the caller is not the profile owner.
+     **/
+    public void setPreferentialNetworkServiceConfig(
+            @NonNull PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
+        throwIfParentInstance("setPreferentialNetworkServiceConfig");
+        if (mService == null) {
+            return;
+        }
+        try {
+            mService.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfig);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get preferential network configuration
+     * {@see PreferentialNetworkServiceConfig}
+     *
+     * <p>This method can be called by the profile owner of a managed profile.
+     *
+     * @return preferential network configuration.
+     * @throws SecurityException if the caller is not the profile owner.
+     */
+    public @NonNull PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() {
+        throwIfParentInstance("getPreferentialNetworkServiceConfig");
+        if (mService == null) {
+            return PreferentialNetworkServiceConfig.DEFAULT;
+        }
+        try {
+            return mService.getPreferentialNetworkServiceConfig();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * This method is mostly deprecated.
      * Most of the settings that still have an effect have dedicated setter methods or user
      * restrictions. See individual settings for details.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index ba08394..927ee0c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -24,6 +24,7 @@
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.admin.ParcelableGranteeMap;
+import android.app.admin.PreferentialNetworkServiceConfig;
 import android.app.admin.StartInstallingUpdateCallback;
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
@@ -267,8 +268,8 @@
     int startUserInBackground(in ComponentName who, in UserHandle userHandle);
     int stopUser(in ComponentName who, in UserHandle userHandle);
     int logoutUser(in ComponentName who);
+    int logoutUserInternal(); // AIDL doesn't allow overloading name (logoutUser())
     int getLogoutUserId();
-    void clearLogoutUser();
     List<UserHandle> getSecondaryUsers(in ComponentName who);
     void acknowledgeNewUserDisclaimer();
 
@@ -286,6 +287,10 @@
     void setPreferentialNetworkServiceEnabled(in boolean enabled);
     boolean isPreferentialNetworkServiceEnabled(int userHandle);
 
+    void setPreferentialNetworkServiceConfig(
+            in PreferentialNetworkServiceConfig preferentialNetworkServiceConfig);
+    PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig();
+
     void setLockTaskPackages(in ComponentName who, in String[] packages);
     String[] getLockTaskPackages(in ComponentName who);
     boolean isLockTaskPermitted(in String pkg);
diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.aidl b/core/java/android/app/admin/PreferentialNetworkServiceConfig.aidl
new file mode 100644
index 0000000..6b6ee7d
--- /dev/null
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR 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.admin;
+
+parcelable PreferentialNetworkServiceConfig;
\ No newline at end of file
diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
new file mode 100644
index 0000000..2849139
--- /dev/null
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.admin;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Network configuration to be set for the user profile
+ * {@see DevicePolicyManager#setPreferentialNetworkServiceConfig}.
+ */
+public final class PreferentialNetworkServiceConfig implements Parcelable {
+    final boolean mIsEnabled;
+    final int mNetworkId;
+    final boolean mAllowFallbackToDefaultConnection;
+    final int[] mIncludedUids;
+    final int[] mExcludedUids;
+
+    /** @hide */
+    public static final PreferentialNetworkServiceConfig DEFAULT =
+            (new PreferentialNetworkServiceConfig.Builder()).build();
+
+    /**
+     * Preferential network identifier 1.
+     */
+    public static final int PREFERENTIAL_NETWORK_ID_1 = 1;
+
+    /**
+     * Preferential network identifier 2.
+     */
+    public static final int PREFERENTIAL_NETWORK_ID_2 = 2;
+
+    /**
+     * Preferential network identifier 3.
+     */
+    public static final int PREFERENTIAL_NETWORK_ID_3 = 3;
+
+    /**
+     * Preferential network identifier 4.
+     */
+    public static final int PREFERENTIAL_NETWORK_ID_4 = 4;
+
+    /**
+     * Preferential network identifier 5.
+     */
+    public static final int PREFERENTIAL_NETWORK_ID_5 = 5;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "PREFERENTIAL_NETWORK_ID_" }, value = {
+            PREFERENTIAL_NETWORK_ID_1,
+            PREFERENTIAL_NETWORK_ID_2,
+            PREFERENTIAL_NETWORK_ID_3,
+            PREFERENTIAL_NETWORK_ID_4,
+            PREFERENTIAL_NETWORK_ID_5,
+    })
+
+    public @interface PreferentialNetworkPreferenceId {
+    }
+
+    private PreferentialNetworkServiceConfig(boolean isEnabled,
+            boolean allowFallbackToDefaultConnection, int[] includedUids,
+            int[] excludedUids, @PreferentialNetworkPreferenceId int networkId) {
+        mIsEnabled = isEnabled;
+        mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection;
+        mIncludedUids = includedUids;
+        mExcludedUids = excludedUids;
+        mNetworkId = networkId;
+    }
+
+    private PreferentialNetworkServiceConfig(Parcel in) {
+        mIsEnabled = in.readBoolean();
+        mAllowFallbackToDefaultConnection = in.readBoolean();
+        mNetworkId = in.readInt();
+        mIncludedUids = in.createIntArray();
+        mExcludedUids = in.createIntArray();
+    }
+
+    /**
+     * Is the preferential network enabled.
+     * @return true if enabled else false
+     */
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    /**
+     * is fallback to default network allowed. This boolean configures whether default connection
+     * (default internet or wifi) should be used or not if a preferential network service
+     * connection is not available.
+     * @return true if fallback is allowed, else false.
+     */
+    public boolean isFallbackToDefaultConnectionAllowed() {
+        return mAllowFallbackToDefaultConnection;
+    }
+
+    /**
+     * Get the array of uids that are applicable for the profile preference.
+     *
+     * {@see #getExcludedUids()}
+     * Included UIDs and Excluded UIDs can't both be non-empty.
+     * if both are empty, it means this request applies to all uids in the user profile.
+     * if included is not empty, then only included UIDs are applied.
+     * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+     * @return Array of uids applicable for the profile preference.
+     *      Empty array would mean that this request applies to all uids in the profile.
+     */
+    public @NonNull int[] getIncludedUids() {
+        return mIncludedUids;
+    }
+
+    /**
+     * Get the array of uids that are excluded for the profile preference.
+     *
+     * {@see #getIncludedUids()}
+     * Included UIDs and Excluded UIDs can't both be non-empty.
+     * if both are empty, it means this request applies to all uids in the user profile.
+     * if included is not empty, then only included UIDs are applied.
+     * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+     * @return Array of uids that are excluded for the profile preference.
+     *      Empty array would mean that this request applies to all uids in the profile.
+     */
+    public @NonNull int[] getExcludedUids() {
+        return mExcludedUids;
+    }
+
+    /**
+     * @return preference enterprise identifier.
+     * valid values starts from
+     * {@link #PREFERENTIAL_NETWORK_ID_1} to {@link #PREFERENTIAL_NETWORK_ID_5}.
+     * preference identifier is applicable only if preference network service is enabled
+     *
+     */
+    public @PreferentialNetworkPreferenceId int getNetworkId() {
+        return mNetworkId;
+    }
+
+    @Override
+    public String toString() {
+        return "PreferentialNetworkServiceConfig{"
+                + "mIsEnabled=" + isEnabled()
+                + "mAllowFallbackToDefaultConnection=" + isFallbackToDefaultConnectionAllowed()
+                + "mIncludedUids=" + mIncludedUids.toString()
+                + "mExcludedUids=" + mExcludedUids.toString()
+                + "mNetworkId=" + mNetworkId
+                + '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        final PreferentialNetworkServiceConfig that = (PreferentialNetworkServiceConfig) o;
+        return mIsEnabled == that.mIsEnabled
+                && mAllowFallbackToDefaultConnection == that.mAllowFallbackToDefaultConnection
+                && mNetworkId == that.mNetworkId
+                && Objects.equals(mIncludedUids, that.mIncludedUids)
+                && Objects.equals(mExcludedUids, that.mExcludedUids);
+    }
+
+    @Override
+    public int hashCode() {
+        return ((Objects.hashCode(mIsEnabled) * 17)
+                + (Objects.hashCode(mAllowFallbackToDefaultConnection) * 19)
+                + (Objects.hashCode(mIncludedUids) * 23)
+                + (Objects.hashCode(mExcludedUids) * 29)
+                + mNetworkId * 31);
+    }
+
+    /**
+     * Builder used to create {@link PreferentialNetworkServiceConfig} objects.
+     * Specify the preferred Network preference
+     */
+    public static final class Builder {
+        boolean mIsEnabled = false;
+        int mNetworkId = 0;
+        boolean mAllowFallbackToDefaultConnection = true;
+        int[] mIncludedUids = new int[0];
+        int[] mExcludedUids = new int[0];
+
+        /**
+         * Constructs an empty Builder with preferential network disabled by default.
+         */
+        public Builder() {}
+
+        /**
+         * Set the preferential network service enabled state.
+         * Default value is false.
+         * @param isEnabled  the desired network preference to use, true to enable else false
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public PreferentialNetworkServiceConfig.Builder setEnabled(boolean isEnabled) {
+            mIsEnabled = isEnabled;
+            return this;
+        }
+
+        /**
+         * Set whether the default connection should be used as fallback.
+         * This boolean configures whether the default connection (default internet or wifi)
+         * should be used if a preferential network service connection is not available.
+         * Default value is true
+         * @param allowFallbackToDefaultConnection  true if fallback is allowed else false
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public PreferentialNetworkServiceConfig.Builder setFallbackToDefaultConnectionAllowed(
+                boolean allowFallbackToDefaultConnection) {
+            mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection;
+            return this;
+        }
+
+        /**
+         * Set the array of uids whose network access will go through this preferential
+         * network service.
+         * {@see #setExcludedUids(int[])}
+         * Included UIDs and Excluded UIDs can't both be non-empty.
+         * if both are empty, it means this request applies to all uids in the user profile.
+         * if included is not empty, then only included UIDs are applied.
+         * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+         * @param uids  array of included uids
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public PreferentialNetworkServiceConfig.Builder setIncludedUids(
+                @NonNull int[] uids) {
+            Objects.requireNonNull(uids);
+            mIncludedUids = uids;
+            return this;
+        }
+
+        /**
+         * Set the array of uids who are not allowed through this preferential
+         * network service.
+         * {@see #setIncludedUids(int[])}
+         * Included UIDs and Excluded UIDs can't both be non-empty.
+         * if both are empty, it means this request applies to all uids in the user profile.
+         * if included is not empty, then only included UIDs are applied.
+         * if excluded is not empty, then it is all uids in the user profile except these UIDs.
+         * @param uids  array of excluded uids
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public PreferentialNetworkServiceConfig.Builder setExcludedUids(
+                @NonNull int[] uids) {
+            Objects.requireNonNull(uids);
+            mExcludedUids = uids;
+            return this;
+        }
+
+        /**
+         * Returns an instance of {@link PreferentialNetworkServiceConfig} created from the
+         * fields set on this builder.
+         */
+        @NonNull
+        public PreferentialNetworkServiceConfig build() {
+            if (mIncludedUids.length > 0 && mExcludedUids.length > 0) {
+                throw new IllegalStateException("Both includedUids and excludedUids "
+                        + "cannot be nonempty");
+            }
+            return new PreferentialNetworkServiceConfig(mIsEnabled,
+                    mAllowFallbackToDefaultConnection, mIncludedUids, mExcludedUids, mNetworkId);
+        }
+
+        /**
+         * Set the preferential network identifier.
+         * Valid values starts from {@link #PREFERENTIAL_NETWORK_ID_1} to
+         * {@link #PREFERENTIAL_NETWORK_ID_5}.
+         * preference identifier is applicable only if preferential network service is enabled.
+         * @param preferenceId  preference Id
+         * @return The builder to facilitate chaining.
+         */
+        @NonNull
+        public PreferentialNetworkServiceConfig.Builder setNetworkId(
+                @PreferentialNetworkPreferenceId int preferenceId) {
+            if ((preferenceId < PREFERENTIAL_NETWORK_ID_1)
+                    || (preferenceId > PREFERENTIAL_NETWORK_ID_5)) {
+                throw new IllegalArgumentException("Invalid preference identifier");
+            }
+            mNetworkId = preferenceId;
+            return this;
+        }
+    }
+
+    @Override
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        dest.writeBoolean(mIsEnabled);
+        dest.writeBoolean(mAllowFallbackToDefaultConnection);
+        dest.writeInt(mNetworkId);
+        dest.writeIntArray(mIncludedUids);
+        dest.writeIntArray(mExcludedUids);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<PreferentialNetworkServiceConfig> CREATOR =
+            new Creator<PreferentialNetworkServiceConfig>() {
+                @Override
+                public PreferentialNetworkServiceConfig[] newArray(int size) {
+                    return new PreferentialNetworkServiceConfig[size];
+                }
+
+                @Override
+                public PreferentialNetworkServiceConfig createFromParcel(
+                        @NonNull android.os.Parcel in) {
+                    return new PreferentialNetworkServiceConfig(in);
+                }
+            };
+}
diff --git a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
index 53af4c5..a46dc53 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
@@ -23,7 +23,7 @@
  *
  * @hide
  */
-interface IVirtualDeviceActivityListener {
+oneway interface IVirtualDeviceActivityListener {
 
     /**
      * Called when the top activity is changed.
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 64f16ac..bb9bb09 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -164,8 +164,6 @@
          * @param executor The executor to run {@code launchCallback} on.
          * @param launchCallback Callback that is called when the pending intent launching is
          *   complete.
-         *
-         * @hide
          */
         public void launchPendingIntent(
                 int displayId,
@@ -196,9 +194,7 @@
 
         /**
          * Creates a virtual display for this virtual device. All displays created on the same
-         * device belongs to the same display group. Requires the ADD_TRUSTED_DISPLAY permission
-         * to create a virtual display which is not in the default DisplayGroup, and to create
-         * trusted displays.
+         * device belongs to the same display group.
          *
          * @param width The width of the virtual display in pixels, must be greater than 0.
          * @param height The height of the virtual display in pixels, must be greater than 0.
@@ -369,9 +365,7 @@
          *
          * @param listener The listener to add.
          * @see #removeActivityListener(ActivityListener)
-         * @hide
          */
-        // TODO(b/194949534): Unhide this API
         public void addActivityListener(@NonNull ActivityListener listener) {
             addActivityListener(listener, mContext.getMainExecutor());
         }
@@ -383,9 +377,7 @@
          * @param listener The listener to add.
          * @param executor The executor where the callback is executed on.
          * @see #removeActivityListener(ActivityListener)
-         * @hide
          */
-        // TODO(b/194949534): Unhide this API
         public void addActivityListener(
                 @NonNull ActivityListener listener, @NonNull Executor executor) {
             mActivityListeners.put(listener, new ActivityListenerDelegate(listener, executor));
@@ -397,9 +389,7 @@
          *
          * @param listener The listener to remove.
          * @see #addActivityListener(ActivityListener, Executor)
-         * @hide
          */
-        // TODO(b/194949534): Unhide this API
         public void removeActivityListener(@NonNull ActivityListener listener) {
             mActivityListeners.remove(listener);
         }
@@ -407,10 +397,7 @@
 
     /**
      * Callback for launching pending intents on the virtual device.
-     *
-     * @hide
      */
-    // TODO(b/194949534): Unhide this API
     public interface LaunchCallback {
         /**
          * Called when the pending intent launched successfully.
@@ -425,10 +412,7 @@
 
     /**
      * Listener for activity changes in this virtual device.
-     *
-     * @hide
      */
-    // TODO(b/194949534): Unhide this API
     public interface ActivityListener {
 
         /**
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index 8d9ef853..f20d1e6 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -29,6 +29,7 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -42,43 +43,125 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
+ * A {@link GenericDocument} representation of {@link ShortcutInfo} object.
  * @hide
  */
 public class AppSearchShortcutInfo extends GenericDocument {
 
+    /** The TTL (time-to-live) of the shortcut, in milli-second. */
+    public static final long SHORTCUT_TTL = TimeUnit.DAYS.toMillis(90);
+
     /** The name of the schema type for {@link ShortcutInfo} documents.*/
     public static final String SCHEMA_TYPE = "Shortcut";
-    public static final int SCHEMA_VERSION = 2;
 
+    /** @hide */
+    public static final int SCHEMA_VERSION = 3;
+
+    /**
+     * Property name of the activity this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#getActivity()}.
+     */
     public static final String KEY_ACTIVITY = "activity";
+
+    /**
+     * Property name of the short description of this {@link ShortcutInfo}.
+     * See {@link ShortcutInfo#getShortLabel()}.
+     */
     public static final String KEY_SHORT_LABEL = "shortLabel";
-    public static final String KEY_SHORT_LABEL_RES_ID = "shortLabelResId";
-    public static final String KEY_SHORT_LABEL_RES_NAME = "shortLabelResName";
+
+    /**
+     * Property name of the long description of this {@link ShortcutInfo}.
+     * See {@link ShortcutInfo#getLongLabel()}.
+     */
     public static final String KEY_LONG_LABEL = "longLabel";
-    public static final String KEY_LONG_LABEL_RES_ID = "longLabelResId";
-    public static final String KEY_LONG_LABEL_RES_NAME = "longLabelResName";
+
+    /**
+     * @hide
+     */
     public static final String KEY_DISABLED_MESSAGE = "disabledMessage";
-    public static final String KEY_DISABLED_MESSAGE_RES_ID = "disabledMessageResId";
-    public static final String KEY_DISABLED_MESSAGE_RES_NAME = "disabledMessageResName";
+
+    /**
+     * Property name of the categories this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#getCategories()}.
+     */
     public static final String KEY_CATEGORIES = "categories";
+
+    /**
+     * Property name of the intents this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#getIntents()}.
+     */
     public static final String KEY_INTENTS = "intents";
+
+    /**
+     * @hide
+     */
     public static final String KEY_INTENT_PERSISTABLE_EXTRAS = "intentPersistableExtras";
+
+    /**
+     * Property name of {@link Person} objects this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#getPersons()}.
+     */
     public static final String KEY_PERSON = "person";
+
+    /**
+     * Property name of {@link LocusId} this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#getLocusId()}.
+     */
     public static final String KEY_LOCUS_ID = "locusId";
-    public static final String KEY_RANK = "rank";
-    public static final String KEY_IMPLICIT_RANK = "implicitRank";
+
+    /**
+     * @hide
+     */
     public static final String KEY_EXTRAS = "extras";
+
+    /**
+     * Property name of the states this {@link ShortcutInfo} is currently in.
+     * Possible values are one or more of the following:
+     *     {@link #IS_DYNAMIC}, {@link #NOT_DYNAMIC}, {@link #IS_MANIFEST}, {@link #NOT_MANIFEST},
+     *     {@link #IS_DISABLED}, {@link #NOT_DISABLED}, {@link #IS_IMMUTABLE},
+     *     {@link #NOT_IMMUTABLE}
+     *
+     */
     public static final String KEY_FLAGS = "flags";
+
+    /**
+     * @hide
+     */
     public static final String KEY_ICON_RES_ID = "iconResId";
+
+    /**
+     * @hide
+     */
     public static final String KEY_ICON_RES_NAME = "iconResName";
+
+    /**
+     * @hide
+     */
     public static final String KEY_ICON_URI = "iconUri";
-    public static final String KEY_BITMAP_PATH = "bitmapPath";
+
+    /**
+     * @hide
+     */
     public static final String KEY_DISABLED_REASON = "disabledReason";
 
+    /**
+     * Property name of capability this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#hasCapability(String)}.
+     */
+    public static final String KEY_CAPABILITY = "capability";
+
+    /**
+     * Property name of capability binding this {@link ShortcutInfo} is associated with.
+     * See {@link ShortcutInfo#getCapabilityParameters(String, String)}.
+     */
+    public static final String KEY_CAPABILITY_BINDINGS = "capabilityBindings";
+
     public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
             .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
@@ -92,50 +175,18 @@
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
                     .build()
 
-            ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_SHORT_LABEL_RES_ID)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .build()
-
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL_RES_NAME)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
-                    .build()
-
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
                     .build()
 
-            ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_LONG_LABEL_RES_ID)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .build()
-
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL_RES_NAME)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
-                    .build()
-
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_MESSAGE)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
                     .build()
 
-            ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(
-                    KEY_DISABLED_MESSAGE_RES_ID)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .build()
-
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
-                    KEY_DISABLED_MESSAGE_RES_NAME)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
-                    .build()
-
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CATEGORIES)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
@@ -154,7 +205,7 @@
                     .build()
 
             ).addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
-                    KEY_PERSON, AppSearchPerson.SCHEMA_TYPE)
+                    KEY_PERSON, AppSearchShortcutPerson.SCHEMA_TYPE)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
                     .build()
 
@@ -164,16 +215,6 @@
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
                     .build()
 
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_RANK)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
-                    .build()
-
-            ).addProperty(new AppSearchSchema.LongPropertyConfig.Builder(KEY_IMPLICIT_RANK)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .build()
-
             ).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_EXTRAS)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .build()
@@ -200,18 +241,24 @@
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
                     .build()
 
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_BITMAP_PATH)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
-                    .build()
-
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_REASON)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
                     .build()
 
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CAPABILITY)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CAPABILITY_BINDINGS)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+                    .build()
+
             ).build();
 
     /**
@@ -219,97 +266,62 @@
      * needs to be camelCase since AppSearch's tokenizer will break the word when it sees
      * underscore.
      */
-    private static final String IS_DYNAMIC = "Dyn";
-    private static final String NOT_DYNAMIC = "nDyn";
-    private static final String IS_PINNED = "Pin";
-    private static final String NOT_PINNED = "nPin";
-    private static final String HAS_ICON_RES = "IcR";
-    private static final String NO_ICON_RES = "nIcR";
-    private static final String HAS_ICON_FILE = "IcF";
-    private static final String NO_ICON_FILE = "nIcF";
-    private static final String IS_KEY_FIELD_ONLY = "Key";
-    private static final String NOT_KEY_FIELD_ONLY = "nKey";
-    private static final String IS_MANIFEST = "Man";
-    private static final String NOT_MANIFEST = "nMan";
-    private static final String IS_DISABLED = "Dis";
-    private static final String NOT_DISABLED = "nDis";
-    private static final String ARE_STRINGS_RESOLVED = "Str";
-    private static final String NOT_STRINGS_RESOLVED = "nStr";
-    private static final String IS_IMMUTABLE = "Im";
-    private static final String NOT_IMMUTABLE = "nIm";
-    private static final String HAS_ADAPTIVE_BITMAP = "IcA";
-    private static final String NO_ADAPTIVE_BITMAP = "nIcA";
-    private static final String IS_RETURNED_BY_SERVICE = "Rets";
-    private static final String NOT_RETURNED_BY_SERVICE = "nRets";
-    private static final String HAS_ICON_FILE_PENDING_SAVE = "Pens";
-    private static final String NO_ICON_FILE_PENDING_SAVE = "nPens";
-    private static final String IS_SHADOW = "Sdw";
-    private static final String NOT_SHADOW = "nSdw";
-    private static final String IS_LONG_LIVED = "Liv";
-    private static final String NOT_LONG_LIVED = "nLiv";
-    private static final String HAS_ICON_URI = "IcU";
-    private static final String NO_ICON_URI = "nIcU";
-    private static final String IS_CACHED_NOTIFICATION = "CaN";
-    private static final String NOT_CACHED_NOTIFICATION = "nCaN";
-    private static final String IS_CACHED_BUBBLE = "CaB";
-    private static final String NOT_CACHED_BUBBLE = "nCaB";
-    private static final String IS_CACHED_PEOPLE_TITLE = "CaPT";
-    private static final String NOT_CACHED_PEOPLE_TITLE = "nCaPT";
 
     /**
-     * Following flags are not store within ShortcutInfo, but book-keeping states to reduce search
-     * space when performing queries against AppSearch.
+     * Indicates the {@link ShortcutInfo} is dynamic shortcut.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isDynamic()}.
      */
-    private static final String HAS_BITMAP_PATH = "hBiP";
-    private static final String HAS_STRING_RESOURCE = "hStr";
-    private static final String HAS_NON_ZERO_RANK = "hRan";
+    public static final String IS_DYNAMIC = "Dyn";
 
-    public static final String QUERY_IS_DYNAMIC = KEY_FLAGS + ":" + IS_DYNAMIC;
-    public static final String QUERY_IS_NOT_DYNAMIC = KEY_FLAGS + ":" + NOT_DYNAMIC;
-    public static final String QUERY_IS_PINNED = KEY_FLAGS + ":" + IS_PINNED;
-    public static final String QUERY_IS_NOT_PINNED = KEY_FLAGS + ":" + NOT_PINNED;
-    public static final String QUERY_IS_MANIFEST = KEY_FLAGS + ":" + IS_MANIFEST;
-    public static final String QUERY_IS_NOT_MANIFEST = KEY_FLAGS + ":" + NOT_MANIFEST;
-    public static final String QUERY_IS_PINNED_AND_ENABLED =
-            "(" + KEY_FLAGS + ":" + IS_PINNED + " " + KEY_FLAGS + ":" + NOT_DISABLED + ")";
-    public static final String QUERY_IS_CACHED =
-            "(" + KEY_FLAGS + ":" + IS_CACHED_NOTIFICATION + " OR "
-            + KEY_FLAGS + ":" + IS_CACHED_BUBBLE + " OR "
-            + KEY_FLAGS + ":" + IS_CACHED_PEOPLE_TITLE + ")";
-    public static final String QUERY_IS_NOT_CACHED =
-            "(" + KEY_FLAGS + ":" + NOT_CACHED_NOTIFICATION + " "
-                    + KEY_FLAGS + ":" + NOT_CACHED_BUBBLE + " "
-                    + KEY_FLAGS + ":" + NOT_CACHED_PEOPLE_TITLE + ")";
-    public static final String QUERY_IS_FLOATING =
-            "((" + IS_PINNED + " OR " + QUERY_IS_CACHED + ") "
-                    + QUERY_IS_NOT_DYNAMIC + " " + QUERY_IS_NOT_MANIFEST + ")";
-    public static final String QUERY_IS_NOT_FLOATING =
-            "((" + QUERY_IS_NOT_PINNED + " " + QUERY_IS_NOT_CACHED + ") OR "
-                    + QUERY_IS_DYNAMIC + " OR " + QUERY_IS_MANIFEST + ")";
-    public static final String QUERY_IS_VISIBLE_TO_PUBLISHER =
-            "(" + KEY_DISABLED_REASON + ":" + ShortcutInfo.DISABLED_REASON_NOT_DISABLED
-                    + " OR " + KEY_DISABLED_REASON + ":"
-                    + ShortcutInfo.DISABLED_REASON_BY_APP
-                    + " OR " + KEY_DISABLED_REASON + ":"
-                    + ShortcutInfo.DISABLED_REASON_APP_CHANGED
-                    + " OR " + KEY_DISABLED_REASON + ":"
-                    + ShortcutInfo.DISABLED_REASON_UNKNOWN + ")";
-    public static final String QUERY_DISABLED_REASON_VERSION_LOWER =
-            KEY_DISABLED_REASON + ":" + ShortcutInfo.DISABLED_REASON_VERSION_LOWER;
-    public static final String QUERY_IS_NON_MANIFEST_VISIBLE =
-            "(" + QUERY_IS_NOT_MANIFEST + " " + QUERY_IS_VISIBLE_TO_PUBLISHER + " ("
-                    + QUERY_IS_PINNED + " OR " + QUERY_IS_CACHED + " OR " + QUERY_IS_DYNAMIC + "))";
-    public static final String QUERY_IS_VISIBLE_CACHED_OR_PINNED =
-            "(" + QUERY_IS_VISIBLE_TO_PUBLISHER + " " + QUERY_IS_DYNAMIC
-                    + " (" + QUERY_IS_CACHED + " OR " + QUERY_IS_PINNED + "))";
-    public static final String QUERY_IS_VISIBLE_PINNED_ONLY =
-            "(" + QUERY_IS_VISIBLE_TO_PUBLISHER + " " + QUERY_IS_PINNED + " " + QUERY_IS_NOT_CACHED
-            + " " + QUERY_IS_NOT_DYNAMIC + " " + QUERY_IS_NOT_MANIFEST + ")";
-    public static final String QUERY_HAS_BITMAP_PATH = KEY_FLAGS + ":" + HAS_BITMAP_PATH;
-    public static final String QUERY_HAS_STRING_RESOURCE = KEY_FLAGS + ":" + HAS_STRING_RESOURCE;
-    public static final String QUERY_HAS_NON_ZERO_RANK = KEY_FLAGS + ":" + HAS_NON_ZERO_RANK;
-    public static final String QUERY_IS_FLOATING_AND_HAS_RANK =
-            "(" + QUERY_IS_FLOATING + " " + QUERY_HAS_NON_ZERO_RANK + ")";
+    /**
+     * Indicates the {@link ShortcutInfo} is not a dynamic shortcut.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isDynamic()}.
+     */
+    public static final String NOT_DYNAMIC = "nDyn";
+
+    /**
+     * Indicates the {@link ShortcutInfo} is manifest shortcut.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isDeclaredInManifest()}.
+     */
+    public static final String IS_MANIFEST = "Man";
+
+    /**
+     * Indicates the {@link ShortcutInfo} is manifest shortcut.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isDeclaredInManifest()}.
+     */
+    public static final String NOT_MANIFEST = "nMan";
+
+    /**
+     * Indicates the {@link ShortcutInfo} is disabled.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isEnabled()}.
+     */
+    public static final String IS_DISABLED = "Dis";
+
+    /**
+     * Indicates the {@link ShortcutInfo} is enabled.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isEnabled()}.
+     */
+    public static final String NOT_DISABLED = "nDis";
+
+    /**
+     * Indicates the {@link ShortcutInfo} was originally from manifest, but currently disabled.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isOriginallyFromManifest()}.
+     */
+    public static final String IS_IMMUTABLE = "Im";
+
+    /**
+     * Indicates the {@link ShortcutInfo} was not originally from manifest.
+     * See {@link #KEY_FLAGS}
+     * See {@link ShortcutInfo#isOriginallyFromManifest()}.
+     */
+    public static final String NOT_IMMUTABLE = "nIm";
 
     public AppSearchShortcutInfo(@NonNull GenericDocument document) {
         super(document);
@@ -324,34 +336,27 @@
         return new Builder(shortcutInfo.getPackage(), shortcutInfo.getId())
                 .setActivity(shortcutInfo.getActivity())
                 .setShortLabel(shortcutInfo.getShortLabel())
-                .setShortLabelResId(shortcutInfo.getShortLabelResourceId())
-                .setShortLabelResName(shortcutInfo.getTitleResName())
                 .setLongLabel(shortcutInfo.getLongLabel())
-                .setLongLabelResId(shortcutInfo.getLongLabelResourceId())
-                .setLongLabelResName(shortcutInfo.getTextResName())
                 .setDisabledMessage(shortcutInfo.getDisabledMessage())
-                .setDisabledMessageResId(shortcutInfo.getDisabledMessageResourceId())
-                .setDisabledMessageResName(shortcutInfo.getDisabledMessageResName())
                 .setCategories(shortcutInfo.getCategories())
                 .setIntents(shortcutInfo.getIntents())
-                .setRank(shortcutInfo.getRank())
-                .setImplicitRank(shortcutInfo.getImplicitRank()
-                        | (shortcutInfo.isRankChanged() ? ShortcutInfo.RANK_CHANGED_BIT : 0))
                 .setExtras(shortcutInfo.getExtras())
                 .setCreationTimestampMillis(shortcutInfo.getLastChangedTimestamp())
                 .setFlags(shortcutInfo.getFlags())
                 .setIconResId(shortcutInfo.getIconResourceId())
                 .setIconResName(shortcutInfo.getIconResName())
-                .setBitmapPath(shortcutInfo.getBitmapPath())
                 .setIconUri(shortcutInfo.getIconUri())
                 .setDisabledReason(shortcutInfo.getDisabledReason())
                 .setPersons(shortcutInfo.getPersons())
                 .setLocusId(shortcutInfo.getLocusId())
+                .setCapabilityBindings(shortcutInfo.getCapabilityBindings())
+                .setTtlMillis(SHORTCUT_TTL)
                 .build();
     }
 
     /**
-     * @hide
+     * Converts this {@link GenericDocument} object into {@link ShortcutInfo} to read the
+     * information.
      */
     @NonNull
     public ShortcutInfo toShortcutInfo(@UserIdInt int userId) {
@@ -367,14 +372,8 @@
         // LauncherApps#getShortcutIconDrawable instead.
         final Icon icon = null;
         final String shortLabel = getPropertyString(KEY_SHORT_LABEL);
-        final int shortLabelResId = (int) getPropertyLong(KEY_SHORT_LABEL_RES_ID);
-        final String shortLabelResName = getPropertyString(KEY_SHORT_LABEL_RES_NAME);
         final String longLabel = getPropertyString(KEY_LONG_LABEL);
-        final int longLabelResId = (int) getPropertyLong(KEY_LONG_LABEL_RES_ID);
-        final String longLabelResName = getPropertyString(KEY_LONG_LABEL_RES_NAME);
         final String disabledMessage = getPropertyString(KEY_DISABLED_MESSAGE);
-        final int disabledMessageResId = (int) getPropertyLong(KEY_DISABLED_MESSAGE_RES_ID);
-        final String disabledMessageResName = getPropertyString(KEY_DISABLED_MESSAGE_RES_NAME);
         final String[] categories = getPropertyStringArray(KEY_CATEGORIES);
         final Set<String> categoriesSet = categories == null
                 ? null : new ArraySet<>(Arrays.asList(categories));
@@ -408,27 +407,22 @@
         final Person[] persons = parsePerson(getPropertyDocumentArray(KEY_PERSON));
         final String locusIdString = getPropertyString(KEY_LOCUS_ID);
         final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
-        final int rank = Integer.parseInt(getPropertyString(KEY_RANK));
-        final int implicitRank = (int) getPropertyLong(KEY_IMPLICIT_RANK);
         final byte[] extrasByte = getPropertyBytes(KEY_EXTRAS);
         final PersistableBundle extras = transformToPersistableBundle(extrasByte);
         final int flags = parseFlags(getPropertyStringArray(KEY_FLAGS));
         final int iconResId = (int) getPropertyLong(KEY_ICON_RES_ID);
         final String iconResName = getPropertyString(KEY_ICON_RES_NAME);
         final String iconUri = getPropertyString(KEY_ICON_URI);
-        final String bitmapPath = getPropertyString(KEY_BITMAP_PATH);
         final int disabledReason = Integer.parseInt(getPropertyString(KEY_DISABLED_REASON));
-        final ShortcutInfo si = new ShortcutInfo(
-                userId, getId(), packageName, activity, icon, shortLabel, shortLabelResId,
-                shortLabelResName, longLabel, longLabelResId, longLabelResName, disabledMessage,
-                disabledMessageResId, disabledMessageResName, categoriesSet, intents, rank, extras,
-                getCreationTimestampMillis(), flags, iconResId, iconResName, bitmapPath, iconUri,
-                disabledReason, persons, locusId, null, null);
-        si.setImplicitRank(implicitRank);
-        if ((implicitRank & ShortcutInfo.RANK_CHANGED_BIT) != 0) {
-            si.setRankChanged();
-        }
-        return si;
+        final Map<String, Map<String, List<String>>> capabilityBindings =
+                parseCapabilityBindings(getPropertyStringArray(KEY_CAPABILITY_BINDINGS));
+        return new ShortcutInfo(
+                userId, getId(), packageName, activity, icon, shortLabel, 0,
+                null, longLabel, 0, null, disabledMessage,
+                0, null, categoriesSet, intents,
+                ShortcutInfo.RANK_NOT_SET, extras, getCreationTimestampMillis(), flags, iconResId,
+                iconResName, null, iconUri, disabledReason, persons, locusId,
+                null, capabilityBindings);
     }
 
     /**
@@ -449,7 +443,6 @@
     public static class Builder extends GenericDocument.Builder<Builder> {
 
         private List<String> mFlags = new ArrayList<>(1);
-        private boolean mHasStringResource = false;
 
         public Builder(String packageName, String id) {
             super(/*namespace=*/ packageName, id, SCHEMA_TYPE);
@@ -493,28 +486,6 @@
          * @hide
          */
         @NonNull
-        public Builder setShortLabelResId(final int shortLabelResId) {
-            setPropertyLong(KEY_SHORT_LABEL_RES_ID, shortLabelResId);
-            if (shortLabelResId != 0) {
-                mHasStringResource = true;
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        public Builder setShortLabelResName(@Nullable final String shortLabelResName) {
-            if (!TextUtils.isEmpty(shortLabelResName)) {
-                setPropertyString(KEY_SHORT_LABEL_RES_NAME, shortLabelResName);
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        @NonNull
         public Builder setLongLabel(@Nullable final CharSequence longLabel) {
             if (!TextUtils.isEmpty(longLabel)) {
                 setPropertyString(KEY_LONG_LABEL, Preconditions.checkStringNotEmpty(
@@ -527,28 +498,6 @@
          * @hide
          */
         @NonNull
-        public Builder setLongLabelResId(final int longLabelResId) {
-            setPropertyLong(KEY_LONG_LABEL_RES_ID, longLabelResId);
-            if (longLabelResId != 0) {
-                mHasStringResource = true;
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        public Builder setLongLabelResName(@Nullable final String longLabelResName) {
-            if (!TextUtils.isEmpty(longLabelResName)) {
-                setPropertyString(KEY_LONG_LABEL_RES_NAME, longLabelResName);
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        @NonNull
         public Builder setDisabledMessage(@Nullable final CharSequence disabledMessage) {
             if (!TextUtils.isEmpty(disabledMessage)) {
                 setPropertyString(KEY_DISABLED_MESSAGE, Preconditions.checkStringNotEmpty(
@@ -561,28 +510,6 @@
          * @hide
          */
         @NonNull
-        public Builder setDisabledMessageResId(final int disabledMessageResId) {
-            setPropertyLong(KEY_DISABLED_MESSAGE_RES_ID, disabledMessageResId);
-            if (disabledMessageResId != 0) {
-                mHasStringResource = true;
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        public Builder setDisabledMessageResName(@Nullable final String disabledMessageResName) {
-            if (!TextUtils.isEmpty(disabledMessageResName)) {
-                setPropertyString(KEY_DISABLED_MESSAGE_RES_NAME, disabledMessageResName);
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        @NonNull
         public Builder setCategories(@Nullable final Set<String> categories) {
             if (categories != null && !categories.isEmpty()) {
                 setPropertyString(KEY_CATEGORIES, categories.stream().toArray(String[]::new));
@@ -649,8 +576,9 @@
             for (int i = 0; i < persons.length; i++) {
                 final Person person = persons[i];
                 if (person == null) continue;
-                final AppSearchPerson appSearchPerson = AppSearchPerson.instance(person);
-                documents[i] = appSearchPerson;
+                final AppSearchShortcutPerson personEntity =
+                        AppSearchShortcutPerson.instance(person);
+                documents[i] = personEntity;
             }
             setPropertyDocument(KEY_PERSON, documents);
             return this;
@@ -660,28 +588,6 @@
          * @hide
          */
         @NonNull
-        public Builder setRank(final int rank) {
-            Preconditions.checkArgument((0 <= rank), "Rank cannot be negative");
-            setPropertyString(KEY_RANK, String.valueOf(rank));
-            if (rank != 0) {
-                mFlags.add(HAS_NON_ZERO_RANK);
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        @NonNull
-        public Builder setImplicitRank(final int rank) {
-            setPropertyLong(KEY_IMPLICIT_RANK, rank);
-            return this;
-        }
-
-        /**
-         * @hide
-         */
-        @NonNull
         public Builder setExtras(@Nullable final PersistableBundle extras) {
             if (extras != null) {
                 setPropertyBytes(KEY_EXTRAS, transformToByteArray(extras));
@@ -722,17 +628,6 @@
         /**
          * @hide
          */
-        public Builder setBitmapPath(@Nullable final String bitmapPath) {
-            if (!TextUtils.isEmpty(bitmapPath)) {
-                setPropertyString(KEY_BITMAP_PATH, bitmapPath);
-                mFlags.add(HAS_BITMAP_PATH);
-            }
-            return this;
-        }
-
-        /**
-         * @hide
-         */
         public Builder setIconUri(@Nullable final String iconUri) {
             if (!TextUtils.isEmpty(iconUri)) {
                 setPropertyString(KEY_ICON_URI, iconUri);
@@ -751,12 +646,33 @@
         /**
          * @hide
          */
+        public Builder setCapabilityBindings(
+                @Nullable final Map<String, Map<String, List<String>>> bindings) {
+            if (bindings != null && !bindings.isEmpty()) {
+                final Set<String> capabilityNames = bindings.keySet();
+                final Set<String> capabilityBindings = new ArraySet<>(1);
+                for (String capabilityName: capabilityNames) {
+                    final Map<String, List<String>> params =
+                            bindings.get(capabilityName);
+                    for (String paramName: params.keySet()) {
+                        params.get(paramName).stream()
+                                .map(v -> capabilityName + "/" + paramName + "/" + v)
+                                .forEach(capabilityBindings::add);
+                    }
+                }
+                setPropertyString(KEY_CAPABILITY, capabilityNames.toArray(new String[0]));
+                setPropertyString(KEY_CAPABILITY_BINDINGS,
+                        capabilityBindings.toArray(new String[0]));
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
         @NonNull
         @Override
         public AppSearchShortcutInfo build() {
-            if (mHasStringResource) {
-                mFlags.add(HAS_STRING_RESOURCE);
-            }
             setPropertyString(KEY_FLAGS, mFlags.toArray(new String[0]));
             return new AppSearchShortcutInfo(super.build());
         }
@@ -827,40 +743,12 @@
         switch (mask) {
             case ShortcutInfo.FLAG_DYNAMIC:
                 return (flags & mask) != 0 ? IS_DYNAMIC : NOT_DYNAMIC;
-            case ShortcutInfo.FLAG_PINNED:
-                return (flags & mask) != 0 ? IS_PINNED : NOT_PINNED;
-            case ShortcutInfo.FLAG_HAS_ICON_RES:
-                return (flags & mask) != 0 ? HAS_ICON_RES : NO_ICON_RES;
-            case ShortcutInfo.FLAG_HAS_ICON_FILE:
-                return (flags & mask) != 0 ? HAS_ICON_FILE : NO_ICON_FILE;
-            case ShortcutInfo.FLAG_KEY_FIELDS_ONLY:
-                return (flags & mask) != 0 ? IS_KEY_FIELD_ONLY : NOT_KEY_FIELD_ONLY;
             case ShortcutInfo.FLAG_MANIFEST:
                 return (flags & mask) != 0 ? IS_MANIFEST : NOT_MANIFEST;
             case ShortcutInfo.FLAG_DISABLED:
                 return (flags & mask) != 0 ? IS_DISABLED : NOT_DISABLED;
-            case ShortcutInfo.FLAG_STRINGS_RESOLVED:
-                return (flags & mask) != 0 ? ARE_STRINGS_RESOLVED : NOT_STRINGS_RESOLVED;
             case ShortcutInfo.FLAG_IMMUTABLE:
                 return (flags & mask) != 0 ? IS_IMMUTABLE : NOT_IMMUTABLE;
-            case ShortcutInfo.FLAG_ADAPTIVE_BITMAP:
-                return (flags & mask) != 0 ? HAS_ADAPTIVE_BITMAP : NO_ADAPTIVE_BITMAP;
-            case ShortcutInfo.FLAG_RETURNED_BY_SERVICE:
-                return (flags & mask) != 0 ? IS_RETURNED_BY_SERVICE : NOT_RETURNED_BY_SERVICE;
-            case ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE:
-                return (flags & mask) != 0 ? HAS_ICON_FILE_PENDING_SAVE : NO_ICON_FILE_PENDING_SAVE;
-            case ShortcutInfo.FLAG_SHADOW:
-                return (flags & mask) != 0 ? IS_SHADOW : NOT_SHADOW;
-            case ShortcutInfo.FLAG_LONG_LIVED:
-                return (flags & mask) != 0 ? IS_LONG_LIVED : NOT_LONG_LIVED;
-            case ShortcutInfo.FLAG_HAS_ICON_URI:
-                return (flags & mask) != 0 ? HAS_ICON_URI : NO_ICON_URI;
-            case ShortcutInfo.FLAG_CACHED_NOTIFICATIONS:
-                return (flags & mask) != 0 ? IS_CACHED_NOTIFICATION : NOT_CACHED_NOTIFICATION;
-            case ShortcutInfo.FLAG_CACHED_BUBBLES:
-                return (flags & mask) != 0 ? IS_CACHED_BUBBLE : NOT_CACHED_BUBBLE;
-            case ShortcutInfo.FLAG_CACHED_PEOPLE_TILE:
-                return (flags & mask) != 0 ? IS_CACHED_PEOPLE_TITLE : NOT_CACHED_PEOPLE_TITLE;
             default:
                 return null;
         }
@@ -881,40 +769,12 @@
         switch (value) {
             case IS_DYNAMIC:
                 return ShortcutInfo.FLAG_DYNAMIC;
-            case IS_PINNED:
-                return ShortcutInfo.FLAG_PINNED;
-            case HAS_ICON_RES:
-                return ShortcutInfo.FLAG_HAS_ICON_RES;
-            case HAS_ICON_FILE:
-                return ShortcutInfo.FLAG_HAS_ICON_FILE;
-            case IS_KEY_FIELD_ONLY:
-                return ShortcutInfo.FLAG_KEY_FIELDS_ONLY;
             case IS_MANIFEST:
                 return ShortcutInfo.FLAG_MANIFEST;
             case IS_DISABLED:
                 return ShortcutInfo.FLAG_DISABLED;
-            case ARE_STRINGS_RESOLVED:
-                return ShortcutInfo.FLAG_STRINGS_RESOLVED;
             case IS_IMMUTABLE:
                 return ShortcutInfo.FLAG_IMMUTABLE;
-            case HAS_ADAPTIVE_BITMAP:
-                return ShortcutInfo.FLAG_ADAPTIVE_BITMAP;
-            case IS_RETURNED_BY_SERVICE:
-                return ShortcutInfo.FLAG_RETURNED_BY_SERVICE;
-            case HAS_ICON_FILE_PENDING_SAVE:
-                return ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE;
-            case IS_SHADOW:
-                return ShortcutInfo.FLAG_SHADOW;
-            case IS_LONG_LIVED:
-                return ShortcutInfo.FLAG_LONG_LIVED;
-            case HAS_ICON_URI:
-                return ShortcutInfo.FLAG_HAS_ICON_URI;
-            case IS_CACHED_NOTIFICATION:
-                return ShortcutInfo.FLAG_CACHED_NOTIFICATIONS;
-            case IS_CACHED_BUBBLE:
-                return ShortcutInfo.FLAG_CACHED_BUBBLES;
-            case IS_CACHED_PEOPLE_TITLE:
-                return ShortcutInfo.FLAG_CACHED_PEOPLE_TILE;
             default:
                 return 0;
         }
@@ -927,9 +787,43 @@
         for (int i = 0; i < persons.length; i++) {
             final GenericDocument document = persons[i];
             if (document == null) continue;
-            final AppSearchPerson person = new AppSearchPerson(document);
+            final AppSearchShortcutPerson person = new AppSearchShortcutPerson(document);
             ret[i] = person.toPerson();
         }
         return ret;
     }
+
+    @Nullable
+    private static Map<String, Map<String, List<String>>> parseCapabilityBindings(
+            @Nullable final String[] capabilityBindings) {
+        if (capabilityBindings == null || capabilityBindings.length == 0) {
+            return null;
+        }
+        final Map<String, Map<String, List<String>>> ret = new ArrayMap<>(1);
+        Arrays.stream(capabilityBindings).forEach(binding -> {
+            if (TextUtils.isEmpty(binding)) {
+                return;
+            }
+            final int capabilityStopIndex = binding.indexOf("/");
+            if (capabilityStopIndex == -1 || capabilityStopIndex == binding.length() - 1) {
+                return;
+            }
+            final String capabilityName = binding.substring(0, capabilityStopIndex);
+            final int paramStopIndex = binding.indexOf("/", capabilityStopIndex + 1);
+            if (paramStopIndex == -1 || paramStopIndex == binding.length() - 1) {
+                return;
+            }
+            final String paramName = binding.substring(capabilityStopIndex + 1, paramStopIndex);
+            final String paramValue = binding.substring(paramStopIndex + 1);
+            if (!ret.containsKey(capabilityName)) {
+                ret.put(capabilityName, new ArrayMap<>(1));
+            }
+            final Map<String, List<String>> params = ret.get(capabilityName);
+            if (!params.containsKey(paramName)) {
+                params.put(paramName, new ArrayList<>(1));
+            }
+            params.get(paramName).add(paramValue);
+        });
+        return ret;
+    }
 }
diff --git a/core/java/android/content/pm/AppSearchPerson.java b/core/java/android/content/pm/AppSearchShortcutPerson.java
similarity index 63%
rename from core/java/android/content/pm/AppSearchPerson.java
rename to core/java/android/content/pm/AppSearchShortcutPerson.java
index 98d150b..ff8a3b6 100644
--- a/core/java/android/content/pm/AppSearchPerson.java
+++ b/core/java/android/content/pm/AppSearchShortcutPerson.java
@@ -21,28 +21,38 @@
 import android.app.Person;
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.GenericDocument;
+import android.graphics.drawable.Icon;
 import android.net.UriCodec;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 import java.util.UUID;
 
 /**
+ * A {@link GenericDocument} representation of {@link Person} object.
+ *
  * @hide
  */
-public class AppSearchPerson extends GenericDocument {
+public class AppSearchShortcutPerson extends GenericDocument {
 
-    /** The name of the schema type for {@link Person} documents.*/
-    public static final String SCHEMA_TYPE = "Person";
+    /**
+     * The name of the schema type for {@link Person} documents.
+     * @hide
+     */
+    public static final String SCHEMA_TYPE = "ShortcutPerson";
 
-    public static final String KEY_NAME = "name";
-    public static final String KEY_KEY = "key";
-    public static final String KEY_IS_BOT = "isBot";
-    public static final String KEY_IS_IMPORTANT = "isImportant";
+    private static final String KEY_NAME = "name";
+    private static final String KEY_KEY = "key";
+    private static final String KEY_IS_BOT = "isBot";
+    private static final String KEY_IS_IMPORTANT = "isImportant";
+    private static final String KEY_ICON = "icon";
 
-    public AppSearchPerson(@NonNull GenericDocument document) {
+    public AppSearchShortcutPerson(@NonNull GenericDocument document) {
         super(document);
     }
 
@@ -67,11 +77,15 @@
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
                     .build()
 
+            ).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_ICON)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
             ).build();
 
-    /** hide */
+    /** @hide */
     @NonNull
-    public static AppSearchPerson instance(@NonNull final Person person) {
+    public static AppSearchShortcutPerson instance(@NonNull final Person person) {
         Objects.requireNonNull(person);
         final String id;
         if (person.getUri() != null) {
@@ -82,10 +96,13 @@
         }
         return new Builder(id).setName(person.getName())
                 .setKey(person.getKey()).setIsBot(person.isBot())
-                .setIsImportant(person.isImportant()).build();
+                .setIsImportant(person.isImportant())
+                .setIcon(transformToByteArray(person.getIcon())).build();
     }
 
-    /** hide */
+    /**
+     * Convert this {@link GenericDocument} into {@link Person}.
+     */
     @NonNull
     public Person toPerson() {
         String uri;
@@ -99,7 +116,9 @@
         return new Person.Builder().setName(getPropertyString(KEY_NAME))
                 .setUri(uri).setKey(getPropertyString(KEY_KEY))
                 .setBot(getPropertyBoolean(KEY_IS_BOT))
-                .setImportant(getPropertyBoolean(KEY_IS_IMPORTANT)).build();
+                .setImportant(getPropertyBoolean(KEY_IS_IMPORTANT))
+                .setIcon(transformToIcon(getPropertyBytes(KEY_ICON)))
+                .build();
     }
 
     /** @hide */
@@ -142,10 +161,51 @@
             return this;
         }
 
+        /** @hide */
+        @NonNull
+        public Builder setIcon(@Nullable final byte[] icon) {
+            if (icon != null) {
+                setPropertyBytes(KEY_ICON, icon);
+            }
+            return this;
+        }
+
+        /** @hide */
         @NonNull
         @Override
-        public AppSearchPerson build() {
-            return new AppSearchPerson(super.build());
+        public AppSearchShortcutPerson build() {
+            return new AppSearchShortcutPerson(super.build());
+        }
+    }
+
+    /**
+     * Convert {@link Icon} into byte[].
+     */
+    @Nullable
+    private static byte[] transformToByteArray(@Nullable final Icon icon) {
+        if (icon == null) {
+            return null;
+        }
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            icon.writeToStream(baos);
+            return baos.toByteArray();
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Convert byte[] into {@link Icon}.
+     */
+    @Nullable
+    private Icon transformToIcon(@Nullable final byte[] icon) {
+        if (icon == null) {
+            return null;
+        }
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(icon)) {
+            return Icon.createFromStream(bais);
+        } catch (IOException e) {
+            return null;
         }
     }
 }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index ab827aa..41dd5bb3 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -24,6 +24,7 @@
 import android.app.Notification;
 import android.app.Person;
 import android.app.TaskStackBuilder;
+import android.app.appsearch.GenericDocument;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -656,6 +657,28 @@
     }
 
     /**
+     * Convert a {@link GenericDocument} into a ShortcutInfo.
+     *
+     * @param context Client context
+     * @param document An instance of {@link GenericDocument} that represents the shortcut.
+     */
+    @NonNull
+    public static ShortcutInfo createFromGenericDocument(@NonNull final Context context,
+            @NonNull final GenericDocument document) {
+        Objects.requireNonNull(context);
+        Objects.requireNonNull(document);
+        return createFromGenericDocument(context.getUserId(), document);
+    }
+
+    /**
+     * @hide
+     */
+    public static ShortcutInfo createFromGenericDocument(
+            final int userId, @NonNull final GenericDocument document) {
+        return new AppSearchShortcutInfo(document).toShortcutInfo(userId);
+    }
+
+    /**
      * Load a string resource from the publisher app.
      *
      * @param resId resource ID
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 459dab1..b617e05 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -136,6 +136,9 @@
     /* Resets the USB gadget. */
     void resetUsbGadget();
 
+    /* Resets the USB port. */
+    boolean resetUsbPort(in String portId, int operationId, in IUsbOperationInternal callback);
+
     /* Set USB data on or off */
     boolean enableUsbData(in String portId, boolean enable, int operationId, in IUsbOperationInternal callback);
 
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f0e040e..60f5135 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -1324,6 +1324,43 @@
     }
 
     /**
+     * Should only be called by {@link UsbPort#resetUsbPort}.
+     * <p>
+     * Disable and then re-enable USB data signaling.
+     *
+     * Reset USB first port..
+     * It will force to stop and restart USB data signaling.
+     * Call UsbPort API if the device has more than one UsbPort.
+     * </p>
+     *
+     * @param port reset the USB Port
+     * @return true enable or disable USB data successfully
+     *         false if something wrong
+     *
+     * Should only be called by {@link UsbPort#resetUsbPort}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    boolean resetUsbPort(@NonNull UsbPort port, int operationId,
+            IUsbOperationInternal callback) {
+        Objects.requireNonNull(port, "resetUsbPort: port must not be null. opId:" + operationId);
+        try {
+            return mService.resetUsbPort(port.getId(), operationId, callback);
+        } catch (RemoteException e) {
+            Log.e(TAG, "resetUsbPort: failed. ", e);
+            try {
+                callback.onOperationComplete(UsbOperationInternal.USB_OPERATION_ERROR_INTERNAL);
+            } catch (RemoteException r) {
+                Log.e(TAG, "resetUsbPort: failed to call onOperationComplete. opId:"
+                        + operationId, r);
+            }
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Should only be called by {@link UsbPort#enableUsbData}.
      * <p>
      * Enables or disables USB data on the specific port.
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index bef4dea..a979725 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -128,6 +128,9 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface EnableUsbDataStatus{}
 
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ResetUsbPortStatus{}
+
     /**
      * The {@link #enableLimitPowerTransfer} request was successfully completed.
      */
@@ -319,6 +322,43 @@
     }
 
     /**
+     * Reset Usb data on the port.
+     *
+     * @return       {@link #ENABLE_USB_DATA_SUCCESS} when request completes successfully or
+     *               {@link #ENABLE_USB_DATA_ERROR_INTERNAL} when request fails due to internal
+     *               error or
+     *               {@link ENABLE_USB_DATA_ERROR_NOT_SUPPORTED} when not supported or
+     *               {@link ENABLE_USB_DATA_ERROR_PORT_MISMATCH} when request fails due to port id
+     *               mismatch or
+     *               {@link ENABLE_USB_DATA_ERROR_OTHER} when fails due to other reasons.
+     */
+    @CheckResult
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public @ResetUsbPortStatus int resetUsbPort() {
+        // UID is added To minimize operationID overlap between two different packages.
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
+        Log.i(TAG, "resetUsbData opId:" + operationId);
+        UsbOperationInternal opCallback =
+                new UsbOperationInternal(operationId, mId);
+        if (mUsbManager.resetUsbPort(this, operationId, opCallback) == true) {
+            opCallback.waitForOperationComplete();
+        }
+        int result = opCallback.getStatus();
+        switch (result) {
+            case USB_OPERATION_SUCCESS:
+                return ENABLE_USB_DATA_SUCCESS;
+            case USB_OPERATION_ERROR_INTERNAL:
+                return ENABLE_USB_DATA_ERROR_INTERNAL;
+            case USB_OPERATION_ERROR_NOT_SUPPORTED:
+                return ENABLE_USB_DATA_ERROR_NOT_SUPPORTED;
+            case USB_OPERATION_ERROR_PORT_MISMATCH:
+                return ENABLE_USB_DATA_ERROR_PORT_MISMATCH;
+            default:
+                return ENABLE_USB_DATA_ERROR_OTHER;
+        }
+    }
+
+    /**
      * Enables/Disables Usb data on the port.
      *
      * @param enable When true enables USB data if disabled.
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 75beacf..f16e243 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -300,13 +300,6 @@
         return false;
     }
 
-    // TODO(b/149463653): remove it in T. We missed the API deadline in S.
-    /** @hide */
-    @Override
-    public final boolean isUiContext() {
-        return true;
-    }
-
     /** @hide */
     @Override
     public final int getWindowType() {
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 7295b72..7bc9573 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -16,19 +16,27 @@
 
 package android.inputmethodservice;
 
+import static android.content.Intent.ACTION_OVERLAY_CHANGED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.inputmethodservice.navigationbar.NavigationBarFrame;
 import android.inputmethodservice.navigationbar.NavigationBarView;
+import android.os.PatternMatcher;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowInsets;
@@ -109,6 +117,9 @@
         @Nullable
         Insets mLastInsets;
 
+        @Nullable
+        private BroadcastReceiver mSystemOverlayChangedReceiver;
+
         Impl(@NonNull InputMethodService inputMethodService) {
             mService = inputMethodService;
         }
@@ -136,6 +147,9 @@
             if (!mRenderGesturalNavButtons) {
                 return;
             }
+            if (mNavigationBarFrame != null) {
+                return;
+            }
             final View rawDecorView = mService.mWindow.getWindow().getDecorView();
             if (!(rawDecorView instanceof ViewGroup)) {
                 return;
@@ -175,6 +189,17 @@
             mNavigationBarFrame.setBackground(null);
         }
 
+        private void uninstallNavigationBarFrameIfNecessary() {
+            if (mNavigationBarFrame == null) {
+                return;
+            }
+            final ViewParent parent = mNavigationBarFrame.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(mNavigationBarFrame);
+            }
+            mNavigationBarFrame = null;
+        }
+
         @Override
         public void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
                 @NonNull ViewTreeObserver.InternalInsetsInfo dest) {
@@ -284,11 +309,38 @@
                 return;
             }
             mRenderGesturalNavButtons = isGesturalNavigationEnabled();
+            if (mSystemOverlayChangedReceiver == null) {
+                final IntentFilter intentFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+                intentFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
+                intentFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
+                mSystemOverlayChangedReceiver = new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (mDestroyed) {
+                            return;
+                        }
+                        mRenderGesturalNavButtons = isGesturalNavigationEnabled();
+                        if (mRenderGesturalNavButtons) {
+                            installNavigationBarFrameIfNecessary();
+                        } else {
+                            uninstallNavigationBarFrameIfNecessary();
+                        }
+                    }
+                };
+                mService.registerReceiver(mSystemOverlayChangedReceiver, intentFilter);
+            }
             installNavigationBarFrameIfNecessary();
         }
 
         @Override
         public void onDestroy() {
+            if (mDestroyed) {
+                return;
+            }
+            if (mSystemOverlayChangedReceiver != null) {
+                mService.unregisterReceiver(mSystemOverlayChangedReceiver);
+                mSystemOverlayChangedReceiver = null;
+            }
             mDestroyed = true;
         }
 
@@ -322,7 +374,9 @@
 
         @Override
         public String toDebugString() {
-            return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons + "}";
+            return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
+                    + " mNavigationBarFrame=" + mNavigationBarFrame
+                    + "}";
         }
     }
 }
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index 539fd4a..e1ccc4f 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -45,4 +45,7 @@
     boolean canMakeReadOnly(int ndefType);
     int getMaxTransceiveLength(int technology);
     boolean getExtendedLengthApdusSupported();
+
+    void setTagUpToDate(long cookie);
+    boolean isTagUpToDate(long cookie);
 }
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 398ec63a..0ce9c70 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -34,6 +34,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.SystemClock;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -121,6 +122,7 @@
     final INfcTag mTagService; // interface to NFC service, will be null if mock tag
 
     int mConnectedTechnology;
+    long mCookie;
 
     /**
      * Hidden constructor to be used by NFC service and internal classes.
@@ -140,6 +142,13 @@
         mTagService = tagService;
 
         mConnectedTechnology = -1;
+
+        try {
+            mCookie = SystemClock.elapsedRealtime();
+            tagService.setTagUpToDate(mCookie);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
     }
 
     /**
@@ -361,6 +370,18 @@
     /** @hide */
     @UnsupportedAppUsage
     public INfcTag getTagService() {
+        try {
+            if (!mTagService.isTagUpToDate(mCookie)) {
+                String id_str = "";
+                for (int i = 0; i < mId.length; i++) {
+                    id_str = id_str + String.format("%02X ", mId[i]);
+                }
+                String msg = "Permission Denial: Tag ( ID: " + id_str + ") is out of date";
+                throw new SecurityException(msg);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
         return mTagService;
     }
 
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 6d4593a..76f857b 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -187,10 +187,13 @@
     public static final int BATTERY_PLUGGED_USB = OsProtoEnums.BATTERY_PLUGGED_USB; // = 2
     /** Power source is wireless. */
     public static final int BATTERY_PLUGGED_WIRELESS = OsProtoEnums.BATTERY_PLUGGED_WIRELESS; // = 4
+    /** Power source is dock. */
+    public static final int BATTERY_PLUGGED_DOCK = OsProtoEnums.BATTERY_PLUGGED_DOCK; // = 8
 
     /** @hide */
     public static final int BATTERY_PLUGGED_ANY =
-            BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS;
+            BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS
+                    | BATTERY_PLUGGED_DOCK;
 
     /**
      * Sent when the device's battery has started charging (or has reached full charge
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index d310d6e..834867c 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -799,6 +799,10 @@
      * Remove any pending posts of messages with code 'what' and whose obj is
      * 'object' that are in the message queue.  If <var>object</var> is null,
      * all messages will be removed.
+     * <p>
+     * Similar to {@link #removeMessages(int, Object)} but uses object equality
+     * ({@link Object#equals(Object)}) instead of reference equality (==) in
+     * determining whether object is the message's obj'.
      *
      *@hide
      */
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d4a338b..b754598 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -44,6 +44,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -612,7 +613,7 @@
     public static final int WAKE_REASON_PLUGGED_IN = 3;
 
     /**
-     * Wake up reason code: Waking up due to a user performed gesture (e.g. douple tapping on the
+     * Wake up reason code: Waking up due to a user performed gesture (e.g. double tapping on the
      * screen).
      * @hide
      */
@@ -703,6 +704,21 @@
         public long wakeTime;
         public @WakeReason int wakeReason;
         public long sleepDuration;
+
+        @Override
+        public boolean equals(@Nullable Object o) {
+            if (o instanceof WakeData) {
+                final WakeData other = (WakeData) o;
+                return wakeTime == other.wakeTime && wakeReason == other.wakeReason
+                        && sleepDuration == other.sleepDuration;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(wakeTime, wakeReason, sleepDuration);
+        }
     }
 
     /**
@@ -1013,7 +1029,7 @@
 
     private static final int MAX_CACHE_ENTRIES = 1;
 
-    private PropertyInvalidatedCache<Void, Boolean> mPowerSaveModeCache =
+    private final PropertyInvalidatedCache<Void, Boolean> mPowerSaveModeCache =
             new PropertyInvalidatedCache<Void, Boolean>(MAX_CACHE_ENTRIES,
                 CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY) {
                 @Override
@@ -1026,7 +1042,7 @@
                 }
             };
 
-    private PropertyInvalidatedCache<Void, Boolean> mInteractiveCache =
+    private final PropertyInvalidatedCache<Void, Boolean> mInteractiveCache =
             new PropertyInvalidatedCache<Void, Boolean>(MAX_CACHE_ENTRIES,
                 CACHE_KEY_IS_INTERACTIVE_PROPERTY) {
                 @Override
@@ -1047,7 +1063,7 @@
     final IThermalService mThermalService;
 
     /** We lazily initialize it.*/
-    private PowerWhitelistManager mPowerWhitelistManager;
+    private PowerExemptionManager mPowerExemptionManager;
 
     private final ArrayMap<OnThermalStatusChangedListener, IThermalStatusListener>
             mListenerMap = new ArrayMap<>();
@@ -1063,12 +1079,12 @@
         mHandler = handler;
     }
 
-    private PowerWhitelistManager getPowerWhitelistManager() {
-        if (mPowerWhitelistManager == null) {
+    private PowerExemptionManager getPowerExemptionManager() {
+        if (mPowerExemptionManager == null) {
             // No need for synchronization; getSystemService() will return the same object anyway.
-            mPowerWhitelistManager = mContext.getSystemService(PowerWhitelistManager.class);
+            mPowerExemptionManager = mContext.getSystemService(PowerExemptionManager.class);
         }
-        return mPowerWhitelistManager;
+        return mPowerExemptionManager;
     }
 
     /**
@@ -1339,12 +1355,12 @@
     }
 
     /**
-     * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+     * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group}
      * to turn off.
      *
-     * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+     * <p>If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is
      * turned on it will be turned off. If all displays are off as a result of this action the
-     * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup#DEFAULT
+     * device will be put to sleep. If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP
      * default display group} is already off then nothing will happen.
      *
      * <p>If the device is an Android TV playback device and the current active source on the
@@ -1372,12 +1388,12 @@
     }
 
     /**
-     * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+     * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group}
      * to turn off.
      *
-     * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+     * <p>If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is
      * turned on it will be turned off. If all displays are off as a result of this action the
-     * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup#DEFAULT
+     * device will be put to sleep. If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP
      * default display group} is already off then nothing will happen.
      *
      * <p>
@@ -1409,12 +1425,12 @@
     }
 
     /**
-     * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+     * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group}
      * to turn on.
      *
-     * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+     * <p>If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is
      * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If
-     * the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is already
+     * the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is already
      * on then nothing will happen.
      *
      * <p>
@@ -1440,12 +1456,12 @@
     }
 
     /**
-     * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+     * Forces the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group}
      * to turn on.
      *
-     * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+     * <p>If the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is
      * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If
-     * the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is already
+     * the {@link android.view.Display#DEFAULT_DISPLAY_GROUP default display group} is already
      * on then nothing will happen.
      *
      * <p>
@@ -2144,7 +2160,7 @@
      * features to the app. Guardrails for extreme cases may still be applied.
      */
     public boolean isIgnoringBatteryOptimizations(String packageName) {
-        return getPowerWhitelistManager().isWhitelisted(packageName, true);
+        return getPowerExemptionManager().isAllowListed(packageName, true);
     }
 
     /**
@@ -2270,8 +2286,8 @@
      * @param listener listener to be added,
      */
     public void addThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        this.addThermalStatusListener(mContext.getMainExecutor(), listener);
+        Objects.requireNonNull(listener, "listener cannot be null");
+        addThermalStatusListener(mContext.getMainExecutor(), listener);
     }
 
     /**
@@ -2282,8 +2298,8 @@
      */
     public void addThermalStatusListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull OnThermalStatusChangedListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        Preconditions.checkNotNull(executor, "executor cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
         Preconditions.checkArgument(!mListenerMap.containsKey(listener),
                 "Listener already registered: %s", listener);
         IThermalStatusListener internalListener = new IThermalStatusListener.Stub() {
@@ -2291,9 +2307,7 @@
             public void onStatusChange(int status) {
                 final long token = Binder.clearCallingIdentity();
                 try {
-                    executor.execute(() -> {
-                        listener.onThermalStatusChanged(status);
-                    });
+                    executor.execute(() -> listener.onThermalStatusChanged(status));
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
@@ -2316,7 +2330,7 @@
      * @param listener listener to be removed
      */
     public void removeThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         IThermalStatusListener internalListener = mListenerMap.get(listener);
         Preconditions.checkArgument(internalListener != null, "Listener was not added");
         try {
@@ -2945,6 +2959,7 @@
          *
          * @hide
          */
+        @SuppressLint("WakelockTimeout")
         public Runnable wrap(Runnable r) {
             acquire();
             return () -> {
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index ae37a71..f490587 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -21,7 +21,6 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
@@ -40,6 +39,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -196,20 +196,20 @@
     /**
      * Create a waveform vibration.
      *
-     * Waveform vibrations are a potentially repeating series of timing and amplitude pairs. For
+     * <p>Waveform vibrations are a potentially repeating series of timing and amplitude pairs. For
      * each pair, the value in the amplitude array determines the strength of the vibration and the
      * value in the timing array determines how long it vibrates for. An amplitude of 0 implies no
      * vibration (i.e. off), and any pairs with a timing value of 0 will be ignored.
-     * <p>
-     * The amplitude array of the generated waveform will be the same size as the given
+     *
+     * <p>The amplitude array of the generated waveform will be the same size as the given
      * timing array with alternating values of 0 (i.e. off) and {@link #DEFAULT_AMPLITUDE},
      * starting with 0. Therefore the first timing value will be the period to wait before turning
      * the vibrator on, the second value will be how long to vibrate at {@link #DEFAULT_AMPLITUDE}
      * strength, etc.
-     * </p><p>
-     * To cause the pattern to repeat, pass the index into the timings array at which to start the
-     * repetition, or -1 to disable repeating.
-     * </p>
+     *
+     * <p>To cause the pattern to repeat, pass the index into the timings array at which to start
+     * the repetition, or -1 to disable repeating. Repeating effects will be played indefinitely
+     * and should be cancelled via {@link Vibrator#cancel()}.
      *
      * @param timings The pattern of alternating on-off timings, starting with off. Timing values
      *                of 0 will cause the timing / amplitude pair to be ignored.
@@ -229,15 +229,15 @@
     /**
      * Create a waveform vibration.
      *
-     * Waveform vibrations are a potentially repeating series of timing and amplitude pairs. For
+     * <p>Waveform vibrations are a potentially repeating series of timing and amplitude pairs. For
      * each pair, the value in the amplitude array determines the strength of the vibration and the
      * value in the timing array determines how long it vibrates for, in milliseconds. Amplitude
      * values must be between 0 and 255, and an amplitude of 0 implies no vibration (i.e. off). Any
      * pairs with a timing value of 0 will be ignored.
-     * </p><p>
-     * To cause the pattern to repeat, pass the index into the timings array at which to start the
-     * repetition, or -1 to disable repeating.
-     * </p>
+     *
+     * <p>To cause the pattern to repeat, pass the index into the timings array at which to start
+     * the repetition, or -1 to disable repeating. Repeating effects will be played indefinitely
+     * and should be cancelled via {@link Vibrator#cancel()}.
      *
      * @param timings The timing values, in milliseconds, of the timing / amplitude pairs. Timing
      *                values of 0 will cause the pair to be ignored.
@@ -407,20 +407,59 @@
      * Start building a waveform vibration.
      *
      * <p>The waveform builder offers more flexibility for creating waveform vibrations, allowing
-     * control over vibration frequency and ramping up or down the vibration amplitude, frequency or
-     * both.
+     * control over vibration amplitude and frequency via smooth transitions between values.
      *
-     * <p>For simpler waveform patterns see {@link #createWaveform} methods.
+     * <p>The waveform will start the first transition from the vibrator off state, with the
+     * resonant frequency by default. To provide an initial state, use
+     * {@link #startWaveform(VibrationParameter)}.
      *
-     * @hide
-     * @see VibrationEffect.WaveformBuilder
+     * @return The {@link VibrationEffect.WaveformBuilder} started with the initial parameters.
      */
-    @TestApi
     @NonNull
     public static WaveformBuilder startWaveform() {
         return new WaveformBuilder();
     }
 
+    /**
+     * Start building a waveform vibration with an initial state specified by a
+     * {@link VibrationParameter}.
+     *
+     * <p>The waveform builder offers more flexibility for creating waveform vibrations, allowing
+     * control over vibration amplitude and frequency via smooth transitions between values.
+     *
+     * @param initialParameter The initial {@link VibrationParameter} value to be applied at the
+     *                         beginning of the vibration.
+     * @return The {@link VibrationEffect.WaveformBuilder} started with the initial parameters.
+     */
+    @NonNull
+    public static WaveformBuilder startWaveform(@NonNull VibrationParameter initialParameter) {
+        WaveformBuilder builder = startWaveform();
+        builder.addTransition(Duration.ZERO, initialParameter);
+        return builder;
+    }
+
+    /**
+     * Start building a waveform vibration with an initial state specified by two
+     * {@link VibrationParameter VibrationParameters}.
+     *
+     * <p>The waveform builder offers more flexibility for creating waveform vibrations, allowing
+     * control over vibration amplitude and frequency via smooth transitions between values.
+     *
+     * @param initialParameter1 The initial {@link VibrationParameter} value to be applied at the
+     *                          beginning of the vibration.
+     * @param initialParameter2 The initial {@link VibrationParameter} value to be applied at the
+     *                          beginning of the vibration, must be a different type of parameter
+     *                          than the one specified by the first argument.
+     * @return The {@link VibrationEffect.WaveformBuilder} started with the initial parameters.
+     */
+    @NonNull
+    public static WaveformBuilder startWaveform(@NonNull VibrationParameter initialParameter1,
+            @NonNull VibrationParameter initialParameter2) {
+        WaveformBuilder builder = startWaveform();
+        builder.addTransition(Duration.ZERO, initialParameter1, initialParameter2);
+        return builder;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -784,10 +823,23 @@
                 PRIMITIVE_LOW_TICK,
         })
         @Retention(RetentionPolicy.SOURCE)
-        public @interface PrimitiveType {}
+        public @interface PrimitiveType {
+        }
+
+        /**
+         * Exception thrown when adding an element to a {@link Composition} that already ends in an
+         * indefinitely repeating effect.
+         */
+        public static final class UnreachableAfterRepeatingIndefinitelyException
+                extends IllegalStateException {
+            UnreachableAfterRepeatingIndefinitelyException() {
+                super("Compositions ending in an indefinitely repeating effect can't be extended");
+            }
+        }
 
         /**
          * No haptic effect. Used to generate extended delays between primitives.
+         *
          * @hide
          */
         public static final int PRIMITIVE_NOOP = 0;
@@ -837,50 +889,87 @@
         Composition() {}
 
         /**
-         * Add a haptic effect to the end of the current composition.
+         * Adds a time duration to the current composition, during which the vibrator will be
+         * turned off
          *
-         * <p>Similar to {@link #addEffect(VibrationEffect, int)} , but with no delay applied.
+         * @param duration The length of time the vibrator should be off. Value must be non-negative
+         *                 and will be truncated to milliseconds.
+         * @return This {@link Composition} object to enable adding multiple elements in one chain.
          *
-         * @param effect The effect to add to this composition as a primitive
-         * @return The {@link Composition} object to enable adding multiple primitives in one chain.
-         * @hide
+         * @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
+         * ending with a repeating effect.
          */
-        @TestApi
         @NonNull
-        public Composition addEffect(@NonNull VibrationEffect effect) {
-            return addEffect(effect, /* delay= */ 0);
+        public Composition addOffDuration(@NonNull Duration duration) {
+            int durationMs = (int) duration.toMillis();
+            Preconditions.checkArgumentNonnegative(durationMs, "Off period must be non-negative");
+            if (durationMs > 0) {
+                // Created a segment sustaining the zero amplitude to represent the delay.
+                addSegment(new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 0,
+                        (int) duration.toMillis()));
+            }
+            return this;
         }
 
         /**
          * Add a haptic effect to the end of the current composition.
          *
-         * @param effect The effect to add to this composition as a primitive
-         * @param delay  The amount of time in milliseconds to wait before playing this primitive
-         * @return The {@link Composition} object to enable adding multiple primitives in one chain.
-         * @hide
+         * <p>If this effect is repeating (e.g. created by {@link VibrationEffect#createWaveform}
+         * with a non-negative repeat index, or created by another composition that has effects
+         * repeating indefinitely), then no more effects or primitives will be accepted by this
+         * composition after this method. Such effects should be cancelled via
+         * {@link Vibrator#cancel()}.
+         *
+         * @param effect The effect to add to the end of this composition.
+         * @return This {@link Composition} object to enable adding multiple elements in one chain.
+         *
+         * @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
+         * ending with a repeating effect.
          */
-        @TestApi
         @NonNull
-        public Composition addEffect(@NonNull VibrationEffect effect,
-                @IntRange(from = 0) int delay) {
-            Preconditions.checkArgumentNonnegative(delay);
-            if (delay > 0) {
-                // Created a segment sustaining the zero amplitude to represent the delay.
-                addSegment(new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 0,
-                        /* duration= */ delay));
-            }
+        public Composition addEffect(@NonNull VibrationEffect effect) {
             return addSegments(effect);
         }
 
         /**
+         * Add a haptic effect to the end of the current composition and play it on repeat,
+         * indefinitely.
+         *
+         * <p>The entire effect will be played on repeat, indefinitely, after all other elements
+         * already added to this composition are played. No more effects or primitives will be
+         * accepted by this composition after this method. Such effects should be cancelled via
+         * {@link Vibrator#cancel()}.
+         *
+         * @param effect The effect to add to the end of this composition, must be finite.
+         * @return This {@link Composition} object to enable adding multiple elements in one chain,
+         * although only {@link #compose()} can follow this call.
+         *
+         * @throws IllegalArgumentException if the given effect is already repeating indefinitely.
+         * @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
+         * ending with a repeating effect.
+         */
+        @NonNull
+        public Composition repeatEffectIndefinitely(@NonNull VibrationEffect effect) {
+            Preconditions.checkArgument(effect.getDuration() < Long.MAX_VALUE,
+                    "Can't repeat an indefinitely repeating effect. Consider addEffect instead.");
+            int previousSegmentCount = mSegments.size();
+            addSegments(effect);
+            // Set repeat after segments were added, since addSegments checks this index.
+            mRepeatIndex = previousSegmentCount;
+            return this;
+        }
+
+        /**
          * Add a haptic primitive to the end of the current composition.
          *
          * Similar to {@link #addPrimitive(int, float, int)}, but with no delay and a
          * default scale applied.
          *
          * @param primitiveId The primitive to add
+         * @return This {@link Composition} object to enable adding multiple elements in one chain.
          *
-         * @return The {@link Composition} object to enable adding multiple primitives in one chain.
+         * @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
+         * ending with a repeating effect.
          */
         @NonNull
         public Composition addPrimitive(@PrimitiveType int primitiveId) {
@@ -894,8 +983,10 @@
          *
          * @param primitiveId The primitive to add
          * @param scale The scale to apply to the intensity of the primitive.
+         * @return This {@link Composition} object to enable adding multiple elements in one chain.
          *
-         * @return The {@link Composition} object to enable adding multiple primitives in one chain.
+         * @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
+         * ending with a repeating effect.
          */
         @NonNull
         public Composition addPrimitive(@PrimitiveType int primitiveId,
@@ -910,7 +1001,10 @@
          * @param scale The scale to apply to the intensity of the primitive.
          * @param delay The amount of time in milliseconds to wait before playing this primitive,
          *              starting at the time the previous element in this composition is finished.
-         * @return The {@link Composition} object to enable adding multiple primitives in one chain.
+         * @return This {@link Composition} object to enable adding multiple elements in one chain.
+         *
+         * @throws UnreachableAfterRepeatingIndefinitelyException if the composition is currently
+         * ending with a repeating effect.
          */
         @NonNull
         public Composition addPrimitive(@PrimitiveType int primitiveId,
@@ -923,9 +1017,7 @@
 
         private Composition addSegment(VibrationEffectSegment segment) {
             if (mRepeatIndex >= 0) {
-                throw new IllegalStateException(
-                        "Composition already have a repeating effect so any new primitive would be"
-                                + " unreachable.");
+                throw new UnreachableAfterRepeatingIndefinitelyException();
             }
             mSegments.add(segment);
             return this;
@@ -933,9 +1025,7 @@
 
         private Composition addSegments(VibrationEffect effect) {
             if (mRepeatIndex >= 0) {
-                throw new IllegalStateException(
-                        "Composition already have a repeating effect so any new primitive would be"
-                                + " unreachable.");
+                throw new UnreachableAfterRepeatingIndefinitelyException();
             }
             Composed composed = (Composed) effect;
             if (composed.getRepeatIndex() >= 0) {
@@ -1001,162 +1091,251 @@
     /**
      * A builder for waveform haptic effects.
      *
-     * <p>Waveform vibrations constitute of one or more timed segments where the vibration
-     * amplitude, frequency or both can linearly ramp to new values.
+     * <p>Waveform vibrations constitute of one or more timed transitions to new sets of vibration
+     * parameters. These parameters can be the vibration amplitude or frequency, for example.
      *
-     * <p>Waveform segments may have zero duration, which represent a jump to new vibration
-     * amplitude and/or frequency values.
+     * <p>Note that physical vibration actuators have different reaction times for changing
+     * amplitude and frequency. Durations specified here represent a timeline for the target
+     * parameters, and quality of effects may be improved if the durations allow time for a
+     * transition to be smoothly applied.
      *
-     * <p>Waveform segments may have the same start and end vibration amplitude and frequency,
-     * which represent a step where the amplitude and frequency are maintained for that duration.
+     * <p>Repeating waveforms can be built by constructing the repeating block separately and adding
+     * it to the end of a composition using
+     * {@link Composition#repeatEffectIndefinitely(VibrationEffect)}.
      *
-     * @hide
-     * @see VibrationEffect#startWaveform()
+     * @see VibrationEffect#startWaveform
      */
-    @TestApi
     public static final class WaveformBuilder {
+        // Epsilon used for float comparison of amplitude and frequency values on transitions.
+        private static final float EPSILON = 1e-5f;
+
         private ArrayList<VibrationEffectSegment> mSegments = new ArrayList<>();
+        private float mLastAmplitude = 0f;
+        private float mLastFrequencyHz = 0f;
 
         WaveformBuilder() {}
 
         /**
-         * Vibrate with given amplitude for the given duration, in millis, keeping the previous
-         * frequency the same.
+         * Add a transition to new vibration parameter value to the end of this waveform.
          *
-         * <p>If the duration is zero the vibrator will jump to new amplitude.
+         * <p>The duration represents how long the vibrator should take to smoothly transition to
+         * the new vibration parameter. If the duration is zero then the vibrator will jump to the
+         * new value as fast as possible.
          *
-         * @param amplitude The amplitude for this step
-         * @param duration  The duration of this step in milliseconds
-         * @return The {@link WaveformBuilder} object to enable adding multiple steps in chain.
+         * <p>Vibration parameter values will be truncated to conform to the device capabilities
+         * according to the {@link android.os.vibrator.VibratorFrequencyProfile}.
+         *
+         * @param duration        The length of time this transition should take. Value must be
+         *                        non-negative and will be truncated to milliseconds.
+         * @param targetParameter The new target {@link VibrationParameter} value to be reached
+         *                        after the given duration.
+         * @return This {@link WaveformBuilder} object to enable adding multiple transitions in
+         * chain.
          */
-        @SuppressLint("MissingGetterMatchingBuilder")
+        @SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created.
         @NonNull
-        public WaveformBuilder addStep(@FloatRange(from = 0f, to = 1f) float amplitude,
-                @IntRange(from = 0) int duration) {
-            mSegments.add(new StepSegment(amplitude, getPreviousFrequencyHz(), duration));
+        public WaveformBuilder addTransition(@NonNull Duration duration,
+                @NonNull VibrationParameter targetParameter) {
+            Preconditions.checkNotNull(duration, "Duration is null");
+            checkVibrationParameter(targetParameter, "targetParameter");
+            float amplitude = extractTargetAmplitude(targetParameter, /* target2= */ null);
+            float frequencyHz = extractTargetFrequency(targetParameter, /* target2= */ null);
+            addTransitionSegment(duration, amplitude, frequencyHz);
             return this;
         }
 
         /**
-         * Vibrate with given amplitude and frequency for the given duration, in millis.
+         * Add a transition to new vibration parameters to the end of this waveform.
          *
-         * <p>If the duration is zero the vibrator will jump to new amplitude.
+         * <p>The duration represents how long the vibrator should take to smoothly transition to
+         * the new vibration parameters. If the duration is zero then the vibrator will jump to the
+         * new values as fast as possible.
          *
-         * @param amplitude The amplitude for this step
-         * @param frequencyHz The frequency for this step, in hertz
-         * @param duration  The duration of this step in milliseconds
-         * @return The {@link WaveformBuilder} object to enable adding multiple steps in chain.
+         * <p>Vibration parameters values will be truncated to conform to the device capabilities
+         * according to the {@link android.os.vibrator.VibratorFrequencyProfile}.
+         *
+         * @param duration         The length of time this transition should take. Value must be
+         *                         non-negative and will be truncated to milliseconds.
+         * @param targetParameter1 The first target {@link VibrationParameter} value to be reached
+         *                         after the given duration.
+         * @param targetParameter2 The second target {@link VibrationParameter} value to be reached
+         *                         after the given duration, must be a different type of parameter
+         *                         than the one specified by the first argument.
+         * @return This {@link WaveformBuilder} object to enable adding multiple transitions in
+         * chain.
          */
-        @SuppressLint("MissingGetterMatchingBuilder")
+        @SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created.
         @NonNull
-        public WaveformBuilder addStep(@FloatRange(from = 0f, to = 1f) float amplitude,
-                @FloatRange(from = 1f) float frequencyHz,
-                @IntRange(from = 0) int duration) {
-            Preconditions.checkArgument(frequencyHz >= 1, "Frequency must be >= 1");
-            mSegments.add(new StepSegment(amplitude, frequencyHz, duration));
+        public WaveformBuilder addTransition(@NonNull Duration duration,
+                @NonNull VibrationParameter targetParameter1,
+                @NonNull VibrationParameter targetParameter2) {
+            Preconditions.checkNotNull(duration, "Duration is null");
+            checkVibrationParameter(targetParameter1, "targetParameter1");
+            checkVibrationParameter(targetParameter2, "targetParameter2");
+            Preconditions.checkArgument(
+                    !Objects.equals(targetParameter1.getClass(), targetParameter2.getClass()),
+                    "Parameter arguments must specify different parameter types");
+            float amplitude = extractTargetAmplitude(targetParameter1, targetParameter2);
+            float frequencyHz = extractTargetFrequency(targetParameter1, targetParameter2);
+            addTransitionSegment(duration, amplitude, frequencyHz);
             return this;
         }
 
         /**
-         * Ramp vibration linearly for the given duration, in millis, from previous amplitude value
-         * to the given one, keeping previous frequency.
+         * Add a duration to sustain the last vibration parameters of this waveform.
          *
-         * <p>If the duration is zero the vibrator will jump to new amplitude.
+         * <p>The duration represents how long the vibrator should sustain the last set of
+         * parameters provided to this builder.
          *
-         * @param amplitude The final amplitude this ramp should reach
-         * @param duration  The duration of this ramp in milliseconds
-         * @return The {@link WaveformBuilder} object to enable adding multiple steps in chain.
+         * @param duration   The length of time the last values should be sustained by the vibrator.
+         *                   Value must be >= 1ms.
+         * @return This {@link WaveformBuilder} object to enable adding multiple transitions in
+         * chain.
          */
-        @SuppressLint("MissingGetterMatchingBuilder")
+        @SuppressWarnings("MissingGetterMatchingBuilder") // No getters to segments once created.
         @NonNull
-        public WaveformBuilder addRamp(@FloatRange(from = 0f, to = 1f) float amplitude,
-                @IntRange(from = 0) int duration) {
-            mSegments.add(new RampSegment(getPreviousAmplitude(), amplitude,
-                    getPreviousFrequencyHz(), getPreviousFrequencyHz(), duration));
+        public WaveformBuilder addSustain(@NonNull Duration duration) {
+            int durationMs = (int) duration.toMillis();
+            Preconditions.checkArgument(durationMs >= 1, "Sustain duration must be >= 1ms");
+            mSegments.add(new StepSegment(mLastAmplitude, mLastFrequencyHz, durationMs));
             return this;
         }
 
         /**
-         * Ramp vibration linearly for the given duration, in millis, from previous amplitude and
-         * frequency values to the given ones.
-         *
-         * <p>If the duration is zero the vibrator will jump to new amplitude and frequency.
-         *
-         * @param amplitude The final amplitude this ramp should reach
-         * @param frequencyHz The final frequency this ramp should reach, in hertz
-         * @param duration  The duration of this ramp in milliseconds
-         * @return The {@link WaveformBuilder} object to enable adding multiple steps in chain.
-         */
-        @SuppressLint("MissingGetterMatchingBuilder")
-        @NonNull
-        public WaveformBuilder addRamp(@FloatRange(from = 0f, to = 1f) float amplitude,
-                @FloatRange(from = 1f) float frequencyHz,
-                @IntRange(from = 0) int duration) {
-            Preconditions.checkArgument(frequencyHz >= 1, "Frequency must be >= 1");
-            mSegments.add(new RampSegment(getPreviousAmplitude(), amplitude,
-                    getPreviousFrequencyHz(), frequencyHz, duration));
-            return this;
-        }
-
-        /**
-         * Compose all the steps together into a single {@link VibrationEffect}.
+         * Build the waveform as a single {@link VibrationEffect}.
          *
          * The {@link WaveformBuilder} object is still valid after this call, so you can
          * continue adding more primitives to it and generating more {@link VibrationEffect}s by
          * calling this method again.
          *
-         * @return The {@link VibrationEffect} resulting from the composition of the steps.
+         * @return The {@link VibrationEffect} resulting from the list of transitions.
          */
         @NonNull
         public VibrationEffect build() {
-            return build(/* repeat= */ -1);
-        }
-
-        /**
-         * Compose all the steps together into a single {@link VibrationEffect}.
-         *
-         * <p>To cause the pattern to repeat, pass the index at which to start the repetition
-         * (starting at 0), or -1 to disable repeating.
-         *
-         * <p>The {@link WaveformBuilder} object is still valid after this call, so you can
-         * continue adding more primitives to it and generating more {@link VibrationEffect}s by
-         * calling this method again.
-         *
-         * @return The {@link VibrationEffect} resulting from the composition of the steps.
-         */
-        @NonNull
-        public VibrationEffect build(int repeat) {
             if (mSegments.isEmpty()) {
                 throw new IllegalStateException(
-                        "WaveformBuilder must have at least one element to build.");
+                        "WaveformBuilder must have at least one transition to build.");
             }
-            VibrationEffect effect = new Composed(mSegments, repeat);
+            VibrationEffect effect = new Composed(mSegments, /* repeatIndex= */ -1);
             effect.validate();
             return effect;
         }
 
-        private float getPreviousFrequencyHz() {
-            if (!mSegments.isEmpty()) {
-                VibrationEffectSegment segment = mSegments.get(mSegments.size() - 1);
-                if (segment instanceof StepSegment) {
-                    return ((StepSegment) segment).getFrequencyHz();
-                } else if (segment instanceof RampSegment) {
-                    return ((RampSegment) segment).getEndFrequencyHz();
-                }
-            }
-            return 0;
+        private void checkVibrationParameter(@NonNull VibrationParameter vibrationParameter,
+                String paramName) {
+            Preconditions.checkNotNull(vibrationParameter, "%s is null", paramName);
+            Preconditions.checkArgument(
+                    (vibrationParameter instanceof AmplitudeVibrationParameter)
+                            || (vibrationParameter instanceof FrequencyVibrationParameter),
+                    "%s is a unknown parameter", paramName);
         }
 
-        private float getPreviousAmplitude() {
-            if (!mSegments.isEmpty()) {
-                VibrationEffectSegment segment = mSegments.get(mSegments.size() - 1);
-                if (segment instanceof StepSegment) {
-                    return ((StepSegment) segment).getAmplitude();
-                } else if (segment instanceof RampSegment) {
-                    return ((RampSegment) segment).getEndAmplitude();
+        private float extractTargetAmplitude(@Nullable VibrationParameter target1,
+                @Nullable VibrationParameter target2) {
+            if (target2 instanceof AmplitudeVibrationParameter) {
+                return ((AmplitudeVibrationParameter) target2).amplitude;
+            }
+            if (target1 instanceof AmplitudeVibrationParameter) {
+                return ((AmplitudeVibrationParameter) target1).amplitude;
+            }
+            return mLastAmplitude;
+        }
+
+        private float extractTargetFrequency(@Nullable VibrationParameter target1,
+                @Nullable VibrationParameter target2) {
+            if (target2 instanceof FrequencyVibrationParameter) {
+                return ((FrequencyVibrationParameter) target2).frequencyHz;
+            }
+            if (target1 instanceof FrequencyVibrationParameter) {
+                return ((FrequencyVibrationParameter) target1).frequencyHz;
+            }
+            return mLastFrequencyHz;
+        }
+
+        private void addTransitionSegment(Duration duration, float targetAmplitude,
+                float targetFrequency) {
+            Preconditions.checkNotNull(duration, "Duration is null");
+            Preconditions.checkArgument(!duration.isNegative(),
+                    "Transition duration must be non-negative");
+            int durationMs = (int) duration.toMillis();
+
+            // Ignore transitions with zero duration, but keep values for next additions.
+            if (durationMs > 0) {
+                if ((Math.abs(mLastAmplitude - targetAmplitude) < EPSILON)
+                        && (Math.abs(mLastFrequencyHz - targetFrequency) < EPSILON)) {
+                    // No value is changing, this can be best represented by a step segment.
+                    mSegments.add(new StepSegment(targetAmplitude, targetFrequency, durationMs));
+                } else {
+                    mSegments.add(new RampSegment(mLastAmplitude, targetAmplitude,
+                            mLastFrequencyHz, targetFrequency, durationMs));
                 }
             }
-            return 0;
+
+            mLastAmplitude = targetAmplitude;
+            mLastFrequencyHz = targetFrequency;
+        }
+    }
+
+    /**
+     * A representation of a single vibration parameter.
+     *
+     * <p>This is to describe a waveform haptic effect, which consists of one or more timed
+     * transitions to a new set of {@link VibrationParameter}s.
+     *
+     * <p>Examples of concrete parameters are the vibration amplitude or frequency.
+     *
+     * @see VibrationEffect.WaveformBuilder
+     */
+    @SuppressWarnings("UserHandleName") // This is not a regular set of parameters, no *Params.
+    public static class VibrationParameter {
+        VibrationParameter() {
+        }
+
+        /**
+         * The target vibration amplitude.
+         *
+         * @param amplitude The amplitude value, between 0 and 1, inclusive, where 0 represents the
+         *                  vibrator turned off and 1 represents the maximum amplitude the vibrator
+         *                  can reach across all supported frequencies.
+         * @return The {@link VibrationParameter} instance that represents given amplitude.
+         */
+        @NonNull
+        public static VibrationParameter targetAmplitude(
+                @FloatRange(from = 0, to = 1) float amplitude) {
+            return new AmplitudeVibrationParameter(amplitude);
+        }
+
+        /**
+         * The target vibration frequency.
+         *
+         * @param frequencyHz The frequency value, in hertz.
+         * @return The {@link VibrationParameter} instance that represents given frequency.
+         */
+        @NonNull
+        public static VibrationParameter targetFrequency(@FloatRange(from = 1) float frequencyHz) {
+            return new FrequencyVibrationParameter(frequencyHz);
+        }
+    }
+
+    /** The vibration amplitude, represented by a value in [0,1]. */
+    private static final class AmplitudeVibrationParameter extends VibrationParameter {
+        public final float amplitude;
+
+        AmplitudeVibrationParameter(float amplitude) {
+            Preconditions.checkArgument((amplitude >= 0) && (amplitude <= 1),
+                    "Amplitude must be within [0,1]");
+            this.amplitude = amplitude;
+        }
+    }
+
+    /** The vibration frequency, in hertz, or zero to represent undefined frequency. */
+    private static final class FrequencyVibrationParameter extends VibrationParameter {
+        public final float frequencyHz;
+
+        FrequencyVibrationParameter(float frequencyHz) {
+            Preconditions.checkArgument(frequencyHz >= 1, "Frequency must be >= 1");
+            Preconditions.checkArgument(Float.isFinite(frequencyHz), "Frequency must be finite");
+            this.frequencyHz = frequencyHz;
         }
     }
 
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index cb5c19b..f4baedc 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -271,6 +272,25 @@
     }
 
     /**
+     * Attempts to force stop and relaunch the game associated with the current session. This may
+     * be useful, for example, after applying settings that will not take effect until the game is
+     * restarted.
+     *
+     * @return {@code true} if the game was successfully restarted; otherwise, {@code false}.
+     */
+    @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+    public final boolean restartGame() {
+        try {
+            mGameSessionController.restartGame(mTaskId);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to restart game", e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
      * Root view of the {@link SurfaceControlViewHost} associated with the {@link GameSession}
      * instance. It is responsible for observing changes in the size of the window and resizing
      * itself to match.
diff --git a/core/java/android/service/games/IGameSessionController.aidl b/core/java/android/service/games/IGameSessionController.aidl
index fe1d362..84311dc 100644
--- a/core/java/android/service/games/IGameSessionController.aidl
+++ b/core/java/android/service/games/IGameSessionController.aidl
@@ -16,6 +16,7 @@
 
 package android.service.games;
 
+import android.content.Intent;
 import com.android.internal.infra.AndroidFuture;
 
 /**
@@ -23,4 +24,6 @@
  */
 oneway interface IGameSessionController {
     void takeScreenshot(int taskId, in AndroidFuture gameScreenshotResultFuture);
-}
\ No newline at end of file
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)")
+    void restartGame(in int taskId);
+}
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 69af2a5..bd468d9 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -17,7 +17,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UiThread;
+import android.graphics.Region;
 import android.hardware.HardwareBuffer;
 
 /**
@@ -124,4 +126,16 @@
     default void removeOnBufferTransformHintChangedListener(
             @NonNull OnBufferTransformHintChangedListener listener) {
     }
+
+    /**
+     * Sets the touchable region for this SurfaceControl, expressed in surface local
+     * coordinates. By default the touchable region is the entire Layer, indicating
+     * that if the layer is otherwise eligible to receive touch it receives touch
+     * on the entire surface. Setting the touchable region allows the SurfaceControl
+     * to receive touch in some regions, while allowing for pass-through in others.
+     *
+     * @param r The region to use or null to use the entire Layer bounds
+     */
+    default void setTouchableRegion(@Nullable Region r) {
+    }
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a2cdc40..ccf1e44 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -339,4 +339,9 @@
      * @param callback The {@link IOnBackInvokedCallback} to set.
      */
     oneway void setOnBackInvokedCallback(IWindow window, IOnBackInvokedCallback callback);
+
+    /**
+     * Clears a touchable region set by {@link #setInsets}.
+     */
+    void clearTouchableRegion(IWindow window);
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e751720b..904d7c8 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -254,6 +254,7 @@
     private static native int nativeGetLayerId(long nativeObject);
     private static native void nativeAddTransactionCommittedListener(long nativeObject,
             TransactionCommittedListener listener);
+    private static native void nativeSanitize(long transactionObject);
 
     /**
      * Transforms that can be applied to buffers as they are displayed to a window.
@@ -3700,6 +3701,13 @@
         }
 
         /**
+         * @hide
+         */
+        public void sanitize() {
+            nativeSanitize(mNativeObject);
+        }
+
+        /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
          *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5ae30bb..1496a4a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -52,6 +52,7 @@
 import static android.view.ViewRootImplProto.WIDTH;
 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
 import static android.view.ViewRootImplProto.WIN_FRAME;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -473,6 +474,9 @@
     final Region mTransparentRegion;
     final Region mPreviousTransparentRegion;
 
+    Region mTouchableRegion;
+    Region mPreviousTouchableRegion;
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     int mWidth;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -3251,9 +3255,15 @@
             mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
         }
 
+        Rect contentInsets = null;
+        Rect visibleInsets = null;
+        Region touchableRegion = null;
+        int touchableInsetMode = TOUCHABLE_INSETS_REGION;
+        boolean computedInternalInsets = false;
         if (computesInternalInsets) {
-            // Clear the original insets.
             final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;
+
+            // Clear the original insets.
             insets.reset();
 
             // Compute new insets in place.
@@ -3265,9 +3275,6 @@
                 mLastGivenInsets.set(insets);
 
                 // Translate insets to screen coordinates if needed.
-                final Rect contentInsets;
-                final Rect visibleInsets;
-                final Region touchableRegion;
                 if (mTranslator != null) {
                     contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
                     visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
@@ -3277,12 +3284,46 @@
                     visibleInsets = insets.visibleInsets;
                     touchableRegion = insets.touchableRegion;
                 }
-
-                try {
-                    mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
-                            contentInsets, visibleInsets, touchableRegion);
-                } catch (RemoteException e) {
+                computedInternalInsets = true;
+            }
+            touchableInsetMode = insets.mTouchableInsets;
+        }
+        boolean needsSetInsets = computedInternalInsets;
+        needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) &&
+            (mTouchableRegion != null);
+        if (needsSetInsets) {
+            if (mTouchableRegion != null) {
+                if (mPreviousTouchableRegion == null) {
+                    mPreviousTouchableRegion = new Region();
                 }
+                mPreviousTouchableRegion.set(mTouchableRegion);
+                if (touchableInsetMode != TOUCHABLE_INSETS_REGION) {
+                    Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" +
+                          " from OnComputeInternalInsets, while also using setTouchableRegion" +
+                          " causes setTouchableRegion to be ignored");
+                }
+            } else {
+                mPreviousTouchableRegion = null;
+            }
+            if (contentInsets == null) contentInsets = new Rect(0,0,0,0);
+            if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0);
+            if (touchableRegion == null) {
+                touchableRegion = mTouchableRegion;
+            } else if (touchableRegion != null && mTouchableRegion != null) {
+                touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION);
+            }
+            try {
+                mWindowSession.setInsets(mWindow, touchableInsetMode,
+                                         contentInsets, visibleInsets, touchableRegion);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else if (mTouchableRegion == null && mPreviousTouchableRegion != null) {
+            mPreviousTouchableRegion = null;
+            try {
+                mWindowSession.clearTouchableRegion(mWindow);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -10706,4 +10747,15 @@
         }
         return mFallbackOnBackInvokedDispatcher;
     }
+
+    @Override
+    public void setTouchableRegion(Region r) {
+        if (r != null) {
+            mTouchableRegion = new Region(r);
+        } else {
+            mTouchableRegion = null;
+        }
+        mLastGivenInsets.reset();
+        requestLayout();
+    }
 }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 577546e..3392edc 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -333,6 +333,11 @@
     }
 
     @Override
+    public void clearTouchableRegion(android.view.IWindow window) {
+        setTouchRegion(window.asBinder(), null);
+    }
+
+    @Override
     public void finishDrawing(android.view.IWindow window,
             android.view.SurfaceControl.Transaction postDrawTransaction) {
         synchronized (this) {
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index f04155d..b90e628 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -151,6 +151,7 @@
         private Instant mIconAnimationStart;
         private Duration mIconAnimationDuration;
         private Consumer<Runnable> mUiThreadInitTask;
+        private boolean mAllowHandleEmpty = true;
 
         public Builder(@NonNull Context context) {
             mContext = context;
@@ -258,6 +259,15 @@
         }
 
         /**
+         * Sets whether this view can be copied and transferred to the client if the view is
+         * empty style splash screen.
+         */
+        public Builder setAllowHandleEmpty(boolean allowHandleEmpty) {
+            mAllowHandleEmpty = allowHandleEmpty;
+            return this;
+        }
+
+        /**
          * Create SplashScreenWindowView object from materials.
          */
         public SplashScreenView build() {
@@ -303,7 +313,7 @@
                 }
                 view.mIconView = imageView;
             }
-            if (mOverlayDrawable != null || mIconDrawable == null) {
+            if (mOverlayDrawable != null || (view.mIconView == null && !mAllowHandleEmpty)) {
                 view.setNotCopyable();
             }
 
@@ -720,13 +730,15 @@
         private RemoteCallback mClientCallback;
 
         public SplashScreenViewParcelable(SplashScreenView view) {
-            mIconSize = view.mIconView.getWidth();
+            final View iconView = view.getIconView();
+            mIconSize = iconView != null ? iconView.getWidth() : 0;
             mBackgroundColor = view.getInitBackgroundColor();
-            mIconBackground = copyDrawable(view.getIconView().getBackground());
+            mIconBackground = iconView != null ? copyDrawable(iconView.getBackground()) : null;
             mSurfacePackage = view.mSurfacePackageCopy;
             if (mSurfacePackage == null) {
                 // We only need to copy the drawable if we are not using a SurfaceView
-                mIconBitmap = copyDrawable(((ImageView) view.getIconView()).getDrawable());
+                mIconBitmap = iconView != null
+                        ? copyDrawable(((ImageView) view.getIconView()).getDrawable()) : null;
             }
             mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
 
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index aec910b..24899a4 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -116,6 +116,7 @@
             TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT,
             TYPE_PARAMETER_ACTIVITY_CREATED,
             TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN,
+            TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN,
             TYPE_PARAMETER_LEGACY_SPLASH_SCREEN
     })
     public @interface StartingTypeParams {}
@@ -141,6 +142,11 @@
      */
     public static final int TYPE_PARAMETER_ACTIVITY_DRAWN = 0x00000040;
     /**
+     * Application is allowed to handle empty splash screen.
+     * @hide
+     */
+    public static final int TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN = 0x00000080;
+    /**
      * Application is allowed to use the legacy splash screen
      * @hide
      */
@@ -185,6 +191,13 @@
         readFromParcel(source);
     }
 
+    /**
+     * Return whether the application allow to handle the empty style splash screen.
+     */
+    public boolean allowHandleEmptySplashScreen() {
+        return (startingWindowTypeParameter & TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN) != 0;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8213c86..25ee2d0 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -13223,59 +13223,57 @@
             long totalRxPackets = 0;
             long totalTxPackets = 0;
             if (delta != null) {
-                NetworkStats.Entry entry = new NetworkStats.Entry();
-                final int size = delta.size();
-                for (int i = 0; i < size; i++) {
-                    entry = delta.getValues(i, entry);
-                    if (entry.rxPackets == 0 && entry.txPackets == 0) {
+                for (NetworkStats.Entry entry : delta) {
+                    if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) {
                         continue;
                     }
 
                     if (DEBUG_ENERGY) {
-                        Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
-                                + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
-                                + " txPackets=" + entry.txPackets);
+                        Slog.d(TAG, "Mobile uid " + entry.getUid() + ": delta rx="
+                                + entry.getRxBytes() + " tx=" + entry.getTxBytes()
+                                + " rxPackets=" + entry.getRxPackets()
+                                + " txPackets=" + entry.getTxPackets());
                     }
 
-                    totalRxPackets += entry.rxPackets;
-                    totalTxPackets += entry.txPackets;
+                    totalRxPackets += entry.getRxPackets();
+                    totalTxPackets += entry.getTxPackets();
 
-                    final Uid u = getUidStatsLocked(mapUid(entry.uid), elapsedRealtimeMs, uptimeMs);
-                    u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
-                            entry.rxPackets);
-                    u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
-                            entry.txPackets);
-                    if (entry.set == NetworkStats.SET_DEFAULT) { // Background transfers
+                    final Uid u = getUidStatsLocked(
+                            mapUid(entry.getUid()), elapsedRealtimeMs, uptimeMs);
+                    u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.getRxBytes(),
+                            entry.getRxPackets());
+                    u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.getTxBytes(),
+                            entry.getTxPackets());
+                    if (entry.getSet() == NetworkStats.SET_DEFAULT) { // Background transfers
                         u.noteNetworkActivityLocked(NETWORK_MOBILE_BG_RX_DATA,
-                                entry.rxBytes, entry.rxPackets);
+                                entry.getRxBytes(), entry.getRxPackets());
                         u.noteNetworkActivityLocked(NETWORK_MOBILE_BG_TX_DATA,
-                                entry.txBytes, entry.txPackets);
+                                entry.getTxBytes(), entry.getTxPackets());
                     }
 
                     mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
-                            entry.rxBytes);
+                            entry.getRxBytes());
                     mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
-                            entry.txBytes);
+                            entry.getTxBytes());
                     mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
-                            entry.rxPackets);
+                            entry.getRxPackets());
                     mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
-                            entry.txPackets);
+                            entry.getTxPackets());
                 }
 
                 // Now distribute proportional blame to the apps that did networking.
                 long totalPackets = totalRxPackets + totalTxPackets;
                 if (totalPackets > 0) {
-                    for (int i = 0; i < size; i++) {
-                        entry = delta.getValues(i, entry);
-                        if (entry.rxPackets == 0 && entry.txPackets == 0) {
+                    for (NetworkStats.Entry entry : delta) {
+                        if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) {
                             continue;
                         }
 
-                        final Uid u = getUidStatsLocked(mapUid(entry.uid),
+                        final Uid u = getUidStatsLocked(mapUid(entry.getUid()),
                                 elapsedRealtimeMs, uptimeMs);
 
                         // Distribute total radio active time in to this app.
-                        final long appPackets = entry.rxPackets + entry.txPackets;
+                        final long appPackets = entry.getRxPackets() + entry.getTxPackets();
                         final long appRadioTimeUs =
                                 (totalAppRadioTimeUs * appPackets) / totalPackets;
                         u.noteMobileRadioActiveTimeLocked(appRadioTimeUs, elapsedRealtimeMs);
@@ -13296,17 +13294,17 @@
                         if (deltaInfo != null) {
                             ControllerActivityCounterImpl activityCounter =
                                     u.getOrCreateModemControllerActivityLocked();
-                            if (totalRxPackets > 0 && entry.rxPackets > 0) {
-                                final long rxMs = (entry.rxPackets
+                            if (totalRxPackets > 0 && entry.getRxPackets() > 0) {
+                                final long rxMs = (entry.getRxPackets()
                                     * deltaInfo.getReceiveTimeMillis()) / totalRxPackets;
                                 activityCounter.getOrCreateRxTimeCounter()
                                         .increment(rxMs, elapsedRealtimeMs);
                             }
 
-                            if (totalTxPackets > 0 && entry.txPackets > 0) {
+                            if (totalTxPackets > 0 && entry.getTxPackets() > 0) {
                                 for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels();
                                         lvl++) {
-                                    long txMs = entry.txPackets
+                                    long txMs = entry.getTxPackets()
                                             * deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
                                     txMs /= totalTxPackets;
                                     activityCounter.getOrCreateTxTimeCounters()[lvl]
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d5470cc..a8cf253 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -953,6 +953,11 @@
     transaction->setDropInputMode(ctrl, static_cast<gui::DropInputMode>(mode));
 }
 
+static void nativeSanitize(JNIEnv* env, jclass clazz, jlong transactionObj) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    transaction->sanitize();
+}
+
 static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
     const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
     jlongArray array = env->NewLongArray(displayIds.size());
@@ -2134,6 +2139,8 @@
              (void*)nativeSetDropInputMode },
     {"nativeAddTransactionCommittedListener", "(JLandroid/view/TransactionCommittedListener;)V",
             (void*) nativeAddTransactionCommittedListener },
+    {"nativeSanitize", "(J)V",
+            (void*) nativeSanitize }
         // clang-format on
 };
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f106872..c62d964 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4205,6 +4205,13 @@
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by a {@link android.media.tv.interactive.TvInteractiveAppService}
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged
+    -->
+    <permission android:name="android.permission.BIND_TV_INTERACTIVE_APP"
+                android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi
          Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
          to ensure that only the system can bind to it.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 02d6293d..5fee1fa 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4600,6 +4600,18 @@
     <array name="config_displayWhiteBalanceDisplayColorTemperatures">
     </array>
 
+    <!-- See DisplayWhiteBalanceController.
+         The same as config_displayWhiteBalanceAmbientColorTemperatures, but with a stronger
+         visual adjustment. -->
+    <array name="config_displayWhiteBalanceStrongAmbientColorTemperatures">
+    </array>
+
+    <!-- See DisplayWhiteBalanceController.
+         The same as config_displayWhiteBalanceDisplayColorTemperatures, but with a stronger
+         visual adjustment. -->
+    <array name="config_displayWhiteBalanceStrongDisplayColorTemperatures">
+    </array>
+
     <!-- All of the paths defined for the batterymeter are defined on a 12x20 canvas, and must
      be parsable by android.utill.PathParser -->
     <string name="config_batterymeterPerimeterPath" translatable="false">
@@ -4944,6 +4956,9 @@
          Used by ChooserActivity. -->
     <string translatable="false" name="config_defaultNearbySharingComponent"></string>
 
+    <!-- URI used for Nearby Share SliceProvider scanning. -->
+    <string translatable="false" name="config_defaultNearbySharingSliceUri"></string>
+
     <!-- Boolean indicating whether frameworks needs to reset cell broadcast geo-fencing
          check after reboot or airplane mode toggling -->
     <bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 3f08e4b..d374b74 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -755,6 +755,8 @@
     <dimen name="item_touch_helper_swipe_escape_velocity">120dp</dimen>
     <dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen>
 
+    <!-- The maximum size of the small notification icon. -->
+    <dimen name="notification_small_icon_size">48dp</dimen>
     <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. This value is determined by the maximum notification height -->
     <dimen name="notification_custom_view_max_image_height">284dp</dimen>
     <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. This value is determined a maximum notification width -->
@@ -779,6 +781,8 @@
     <!-- The alpha of a disabled notification button -->
     <item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item>
 
+    <!-- The maximum size of the small notification icon on low memory devices. -->
+    <dimen name="notification_small_icon_size_low_ram">@dimen/notification_small_icon_size</dimen>
     <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
     <dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen>
     <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8bf6caa..59ad302 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -197,7 +197,7 @@
     <string name="ThreeWCMmi">Three way calling</string>
     <string name="RuacMmi">Rejection of undesired annoying calls</string>
     <string name="CndMmi">Calling number delivery</string>
-    <string name="DndMmi">Do not disturb</string>
+    <string name="DndMmi" translatable="false">Priority mode</string>
 
     <!-- Displayed to confirm to the user that caller ID will be restricted on the next call as usual. -->
     <string name="CLIRDefaultOnNextCallOn">Caller ID defaults to restricted. Next call: Restricted</string>
@@ -2029,9 +2029,9 @@
     <string name="permdesc_bindCarrierServices">Allows the holder to bind to carrier services. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, for applications that wish to access notification policy. -->
-    <string name="permlab_access_notification_policy">access Do Not Disturb</string>
+    <string name="permlab_access_notification_policy" translatable="false">access Priority mode</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_access_notification_policy">Allows the app to read and write Do Not Disturb configuration.</string>
+    <string name="permdesc_access_notification_policy" translatable="false">Allows the app to read and write Priority mode configuration.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_startViewPermissionUsage">start view permission usage</string>
@@ -5294,7 +5294,7 @@
     <string name="zen_mode_forever">Until you turn off</string>
 
     <!-- Zen mode condition: no exit criteria, includes the name of the feature for emphasis. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_forever_dnd">Until you turn off Do Not Disturb</string>
+    <string name="zen_mode_forever_dnd" translatable="false">Until you turn off Priority mode</string>
 
     <!-- Zen mode active automatic rule name separator. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_rule_name_combination"><xliff:g id="first" example="Weeknights">%1$s</xliff:g> / <xliff:g id="rest" example="Meetings">%2$s</xliff:g></string>
@@ -5303,7 +5303,7 @@
     <string name="toolbar_collapse_description">Collapse</string>
 
     <!-- Zen mode - feature name. [CHAR LIMIT=40] -->
-    <string name="zen_mode_feature_name">Do not disturb</string>
+    <string name="zen_mode_feature_name" translatable="false">Priority mode</string>
 
     <!-- Zen mode - downtime legacy feature name. [CHAR LIMIT=40] -->
     <string name="zen_mode_downtime_feature_name">Downtime</string>
@@ -5719,14 +5719,14 @@
 
     <!-- Title for the notification channel notifying user of settings system changes. [CHAR LIMIT=NONE] -->
     <string name="notification_channel_system_changes">System changes</string>
-    <!-- Title for the notification channel notifying user of do not disturb system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
-    <string name="notification_channel_do_not_disturb">Do Not Disturb</string>
-    <!-- Title of notification indicating do not disturb visual interruption settings have changed when upgrading to P -->
-    <string name="zen_upgrade_notification_visd_title">New: Do Not Disturb is hiding notifications</string>
+    <!-- Title for the notification channel notifying user of priority mode system changes (i.e. Priority mode has changed). [CHAR LIMIT=NONE] -->
+    <string name="notification_channel_do_not_disturb" translatable="false">Priority mode</string>
+    <!-- Title of notification indicating Priority mode visual interruption settings have changed when upgrading to P -->
+    <string name="zen_upgrade_notification_visd_title" translatable="false">New: Priority mode is hiding notifications</string>
     <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
     <string name="zen_upgrade_notification_visd_content">Tap to learn more and change.</string>
-    <!-- Title of notification indicating do not disturb settings have changed when upgrading to P -->
-    <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string>
+    <!-- Title of notification indicating priority mode settings have changed when upgrading to P -->
+    <string name="zen_upgrade_notification_title" translatable="false">Priority mode has changed</string>
     <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
     <string name="zen_upgrade_notification_content">Tap to check what\'s blocked.</string>
 
@@ -5767,7 +5767,7 @@
     <!-- Label of notification action button to learn more about the enhanced notifications [CHAR LIMIT=20] -->
     <string name="nas_upgrade_notification_learn_more_action">Learn more</string>
     <!-- Content of notification learn more dialog about the enhanced notifications [CHAR LIMIT=NONE] -->
-    <string name="nas_upgrade_notification_learn_more_content">Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Do Not Disturb.</string>
+    <string name="nas_upgrade_notification_learn_more_content" translatable="false">Enhanced notifications replaced Android Adaptive Notifications in Android 12. This feature shows suggested actions and replies, and organizes your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Priority mode.</string>
 
 
     <!-- Dynamic mode battery saver strings -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4d8f9a2..6ae2829 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3561,6 +3561,7 @@
   <java-symbol type="style" name="Theme.DeviceDefault.Autofill.Save" />
   <java-symbol type="style" name="Theme.DeviceDefault.Light.Autofill.Save" />
 
+  <java-symbol type="dimen" name="notification_small_icon_size"/>
   <java-symbol type="dimen" name="notification_big_picture_max_height"/>
   <java-symbol type="dimen" name="notification_big_picture_max_width"/>
   <java-symbol type="dimen" name="notification_right_icon_size"/>
@@ -3569,6 +3570,7 @@
   <java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
   <java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
 
+  <java-symbol type="dimen" name="notification_small_icon_size_low_ram"/>
   <java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
   <java-symbol type="dimen" name="notification_big_picture_max_width_low_ram"/>
   <java-symbol type="dimen" name="notification_right_icon_size_low_ram"/>
@@ -3980,6 +3982,8 @@
   <java-symbol type="dimen" name="config_displayWhiteBalanceHighLightAmbientColorTemperature" />
   <java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" />
+  <java-symbol type="array" name="config_displayWhiteBalanceStrongAmbientColorTemperatures" />
+  <java-symbol type="array" name="config_displayWhiteBalanceStrongDisplayColorTemperatures" />
   <java-symbol type="drawable" name="ic_action_open" />
   <java-symbol type="drawable" name="ic_menu_copy_material" />
 
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 37cf514..e6d2364 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -39,6 +39,7 @@
 import android.content.LocusId;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
@@ -504,6 +505,22 @@
     }
 
     @Test
+    public void testBuild_ensureSmallIconIsNotTooBig_resizesIcon() {
+        Icon hugeIcon = Icon.createWithBitmap(
+                Bitmap.createBitmap(3000, 3000, Bitmap.Config.ARGB_8888));
+        Notification notification = new Notification.Builder(mContext, "Channel").setSmallIcon(
+                hugeIcon).build();
+
+        Bitmap smallNotificationIcon = notification.getSmallIcon().getBitmap();
+        assertThat(smallNotificationIcon.getWidth()).isEqualTo(
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.notification_small_icon_size));
+        assertThat(smallNotificationIcon.getHeight()).isEqualTo(
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.notification_small_icon_size));
+    }
+
+    @Test
     public void testColors_ensureColors_dayMode_producesValidPalette() {
         Notification.Colors c = new Notification.Colors();
         boolean colorized = false;
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchPersonTest.java b/core/tests/coretests/src/android/content/pm/AppSearchShortcutPersonTest.java
similarity index 92%
rename from core/tests/coretests/src/android/content/pm/AppSearchPersonTest.java
rename to core/tests/coretests/src/android/content/pm/AppSearchShortcutPersonTest.java
index 5ba9059..3c49481 100644
--- a/core/tests/coretests/src/android/content/pm/AppSearchPersonTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppSearchShortcutPersonTest.java
@@ -24,7 +24,7 @@
 import org.junit.Test;
 
 @Presubmit
-public class AppSearchPersonTest {
+public class AppSearchShortcutPersonTest {
 
     @Test
     public void testBuildPersonAndGetValue() {
@@ -32,7 +32,7 @@
         final String key = "key";
         final String uri = "name:name";
 
-        final Person person = new AppSearchPerson.Builder(uri)
+        final Person person = new AppSearchShortcutPerson.Builder(uri)
                 .setName(name)
                 .setKey(key)
                 .setIsBot(true)
diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java
index 10cec82..104f077 100644
--- a/core/tests/coretests/src/android/os/VibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java
@@ -16,6 +16,9 @@
 
 package android.os;
 
+import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
+import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -32,6 +35,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.VibrationEffect.Composition.UnreachableAfterRepeatingIndefinitelyException;
 import android.os.vibrator.PrebakedSegment;
 import android.os.vibrator.PrimitiveSegment;
 import android.os.vibrator.StepSegment;
@@ -43,6 +47,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.time.Duration;
+
 @Presubmit
 @RunWith(MockitoJUnitRunner.class)
 public class VibrationEffectTest {
@@ -122,16 +128,7 @@
         VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, -1).validate();
         VibrationEffect.createWaveform(new long[]{10, 10}, new int[] {0, 0}, -1).validate();
         VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, 0).validate();
-        VibrationEffect.startWaveform()
-                .addStep(/* amplitude= */ 1, /* duration= */ 10)
-                .addRamp(/* amplitude= */ 0, /* duration= */ 20)
-                .addStep(/* amplitude= */ 1, /* frequencyHz= */ 1, /* duration= */ 100)
-                .addRamp(/* amplitude= */ 0.5f, /* frequencyHz= */ 100, /* duration= */ 50)
-                .build()
-                .validate();
 
-        assertThrows(IllegalStateException.class,
-                () -> VibrationEffect.startWaveform().build().validate());
         assertThrows(IllegalArgumentException.class,
                 () -> VibrationEffect.createWaveform(new long[0], new int[0], -1).validate());
         assertThrows(IllegalArgumentException.class,
@@ -145,27 +142,31 @@
         assertThrows(IllegalArgumentException.class,
                 () -> VibrationEffect.createWaveform(
                         TEST_TIMINGS, TEST_AMPLITUDES, TEST_TIMINGS.length).validate());
+    }
+
+    @Test
+    public void testValidateWaveformBuilder() {
+        VibrationEffect.startWaveform(targetAmplitude(1))
+                .addTransition(Duration.ofSeconds(1), targetAmplitude(0.5f), targetFrequency(100))
+                .addTransition(Duration.ZERO, targetAmplitude(0f), targetFrequency(200))
+                .addSustain(Duration.ofMinutes(2))
+                .addTransition(Duration.ofMillis(10), targetAmplitude(1f), targetFrequency(50))
+                .addSustain(Duration.ofMillis(1))
+                .addTransition(Duration.ZERO, targetFrequency(150))
+                .addSustain(Duration.ofMillis(2))
+                .addTransition(Duration.ofSeconds(15), targetAmplitude(1))
+                .build()
+                .validate();
+
+        assertThrows(IllegalStateException.class,
+                () -> VibrationEffect.startWaveform().build().validate());
+        assertThrows(IllegalArgumentException.class, () -> targetAmplitude(-2));
+        assertThrows(IllegalArgumentException.class, () -> targetFrequency(0));
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addStep(/* amplitude= */ -2, 10).build().validate());
+                () -> VibrationEffect.startWaveform().addTransition(
+                        Duration.ofMillis(-10), targetAmplitude(1)).build().validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addStep(1, /* frequencyHz= */ -1f, 10).build().validate());
-        assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addStep(1, /* duration= */ -1).build().validate());
-        assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addStep(1, 100f, /* duration= */ -1).build().validate());
-        assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addRamp(/* amplitude= */ -3, 10).build().validate());
-        assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addRamp(1, /* frequencyHz= */ 0, 10).build().validate());
-        assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveform()
-                        .addRamp(1, 10f, /* duration= */ -3).build().validate());
+                () -> VibrationEffect.startWaveform().addSustain(Duration.ZERO).build().validate());
     }
 
     @Test
@@ -174,14 +175,24 @@
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
                 .addEffect(TEST_ONE_SHOT)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
-                .addEffect(TEST_WAVEFORM, 100)
+                .addOffDuration(Duration.ofMillis(100))
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
                 .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .compose()
                 .validate();
 
+        VibrationEffect.startComposition()
+                .repeatEffectIndefinitely(TEST_ONE_SHOT)
+                .compose()
+                .validate();
+
         assertThrows(IllegalStateException.class,
                 () -> VibrationEffect.startComposition().compose().validate());
+        assertThrows(IllegalStateException.class,
+                () -> VibrationEffect.startComposition()
+                        .addOffDuration(Duration.ofSeconds(0))
+                        .compose()
+                        .validate());
         assertThrows(IllegalArgumentException.class,
                 () -> VibrationEffect.startComposition().addPrimitive(-1).compose().validate());
         assertThrows(IllegalArgumentException.class,
@@ -196,12 +207,27 @@
                         .validate());
         assertThrows(IllegalArgumentException.class,
                 () -> VibrationEffect.startComposition()
-                        .addEffect(TEST_ONE_SHOT, /* delay= */ -10)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, -1)
                         .compose()
                         .validate());
         assertThrows(IllegalArgumentException.class,
                 () -> VibrationEffect.startComposition()
-                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, -1)
+                        .repeatEffectIndefinitely(
+                                // Repeating waveform.
+                                VibrationEffect.createWaveform(
+                                        new long[] { 10 }, new int[] { 100}, 0))
+                        .compose()
+                        .validate());
+        assertThrows(UnreachableAfterRepeatingIndefinitelyException.class,
+                () -> VibrationEffect.startComposition()
+                        .repeatEffectIndefinitely(TEST_WAVEFORM)
+                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                        .compose()
+                        .validate());
+        assertThrows(UnreachableAfterRepeatingIndefinitelyException.class,
+                () -> VibrationEffect.startComposition()
+                        .repeatEffectIndefinitely(TEST_WAVEFORM)
+                        .addEffect(TEST_ONE_SHOT)
                         .compose()
                         .validate());
     }
@@ -354,9 +380,9 @@
         assertFalse(VibrationEffect.createWaveform(
                 new long[]{200, 200, 700}, new int[]{1, 2, 3}, -1).isHapticFeedbackCandidate());
         assertFalse(VibrationEffect.startWaveform()
-                .addRamp(1, 500)
-                .addStep(1, 200)
-                .addRamp(0, 500)
+                .addTransition(Duration.ofMillis(500), targetAmplitude(1))
+                .addTransition(Duration.ofMillis(200), targetAmplitude(0.5f))
+                .addTransition(Duration.ofMillis(500), targetAmplitude(0))
                 .build()
                 .isHapticFeedbackCandidate());
     }
@@ -367,9 +393,9 @@
         assertTrue(VibrationEffect.createWaveform(
                 new long[]{100, 200, 300}, new int[]{1, 2, 3}, -1).isHapticFeedbackCandidate());
         assertTrue(VibrationEffect.startWaveform()
-                .addRamp(1, 300)
-                .addStep(1, 200)
-                .addRamp(0, 300)
+                .addTransition(Duration.ofMillis(300), targetAmplitude(1))
+                .addTransition(Duration.ofMillis(200), targetAmplitude(0.5f))
+                .addTransition(Duration.ofMillis(300), targetAmplitude(0))
                 .build()
                 .isHapticFeedbackCandidate());
     }
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 69ff7c6..cd42a34 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -81,6 +81,7 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.service.chooser.ChooserTarget;
+import android.util.Log;
 import android.view.View;
 
 import androidx.annotation.CallSuper;
@@ -187,7 +188,7 @@
      * TODO: remove when we no longer want to test the system's on-the-fly evaluation.
      */
     protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() {
-        return true;
+        return false;
     }
 
     /* --------
@@ -762,6 +763,7 @@
 
 
     @Test
+    @Ignore
     public void testNearbyShareLogging() throws Exception {
         Intent sendIntent = createSendTextIntent();
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1327,16 +1329,17 @@
         final ChooserActivity activity =
                 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-
         if (activity.getPackageManager().getAppPredictionServicePackageName() == null) {
             assertThat(activity.isAppPredictionServiceAvailable(), is(false));
         } else {
-            assertThat(activity.isAppPredictionServiceAvailable(), is(true));
-
             if (!shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()) {
                 return;
             }
 
+            // This isn't a toggle per-se, but isAppPredictionServiceAvailable only works in
+            // system (see comment in the method).
+            assertThat(activity.isAppPredictionServiceAvailable(), is(true));
+
             ChooserActivityOverrideData.getInstance().resources =
                     Mockito.spy(activity.getResources());
             when(
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 d4f08ba..7f85982 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -51,6 +51,13 @@
     static final ChooserActivityOverrideData sOverrides = ChooserActivityOverrideData.getInstance();
     private UsageStatsManager mUsm;
 
+    // ResolverActivity (the base class of ChooserActivity) inspects the launched-from UID at
+    // onCreate and needs to see some non-negative value in the test.
+    @Override
+    public int getLaunchedFromUid() {
+        return 1234;
+    }
+
     @Override
     protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
             Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed) {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index eefad8d..afd320d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2184,9 +2184,13 @@
                     contextCount, isRtl, outMetrics);
         } else {
             char[] buf = TemporaryBuffer.obtain(contextCount);
-            TextUtils.getChars(text, contextStart, contextStart + contextCount, buf, 0);
-            nGetFontMetricsIntForText(mNativePaint, buf, start - contextStart, count, 0,
-                    contextCount, isRtl, outMetrics);
+            try {
+                TextUtils.getChars(text, contextStart, contextStart + contextCount, buf, 0);
+                nGetFontMetricsIntForText(mNativePaint, buf, start - contextStart, count, 0,
+                        contextCount, isRtl, outMetrics);
+            } finally {
+                TemporaryBuffer.recycle(buf);
+            }
         }
 
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 6921448..3e6dc82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -137,6 +137,9 @@
     private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider;
 
     private StageCoordinator mStageCoordinator;
+    // Only used for the legacy recents animation from splitscreen to allow the tasks to be animated
+    // outside the bounds of the roots by being reparented into a higher level fullscreen container
+    private SurfaceControl mSplitTasksContainerLayer;
 
     public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue, Context context,
@@ -378,20 +381,24 @@
     RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, RemoteAnimationTarget[] apps) {
         if (ENABLE_SHELL_TRANSITIONS || apps.length < 2) return null;
         // TODO(b/206487881): Integrate this with shell transition.
+        SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+        if (mSplitTasksContainerLayer != null) {
+            // Remove the previous layer before recreating
+            transaction.remove(mSplitTasksContainerLayer);
+        }
         final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
                 .setContainerLayer()
                 .setName("RecentsAnimationSplitTasks")
                 .setHidden(false)
                 .setCallsite("SplitScreenController#onGoingtoRecentsLegacy");
         mRootTDAOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, builder);
-        SurfaceControl sc = builder.build();
-        SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+        mSplitTasksContainerLayer = builder.build();
 
         // Ensure that we order these in the parent in the right z-order as their previous order
         Arrays.sort(apps, (a1, a2) -> a1.prefixOrderIndex - a2.prefixOrderIndex);
         int layer = 1;
         for (RemoteAnimationTarget appTarget : apps) {
-            transaction.reparent(appTarget.leash, sc);
+            transaction.reparent(appTarget.leash, mSplitTasksContainerLayer);
             transaction.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
                     appTarget.screenSpaceBounds.top);
             transaction.setLayer(appTarget.leash, layer++);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 413627d..e255e44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -54,6 +54,7 @@
 import android.view.SurfaceControl;
 import android.view.View;
 import android.window.SplashScreenView;
+import android.window.StartingWindowInfo;
 import android.window.StartingWindowInfo.StartingWindowType;
 
 import com.android.internal.R;
@@ -138,8 +139,8 @@
      *                                 executed on splash screen thread. Note that the view can be
      *                                 null if failed.
      */
-    void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
-            int taskId, Consumer<SplashScreenView> splashScreenViewConsumer,
+    void createContentView(Context context, @StartingWindowType int suggestType,
+            StartingWindowInfo info, Consumer<SplashScreenView> splashScreenViewConsumer,
             Consumer<Runnable> uiThreadInitConsumer) {
         mSplashscreenWorkerHandler.post(() -> {
             SplashScreenView contentView;
@@ -150,7 +151,7 @@
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "failed creating starting window content at taskId: "
-                        + taskId, e);
+                        + info.taskInfo.taskId, e);
                 contentView = null;
             }
             splashScreenViewConsumer.accept(contentView);
@@ -241,7 +242,7 @@
         return null;
     }
 
-    private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
+    private SplashScreenView makeSplashScreenContentView(Context context, StartingWindowInfo info,
             @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) {
         updateDensity();
 
@@ -250,6 +251,9 @@
 
         final Drawable legacyDrawable = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
                 ? peekLegacySplashscreenContent(context, mTmpAttrs) : null;
+        final ActivityInfo ai = info.targetActivityInfo != null
+                ? info.targetActivityInfo
+                : info.taskInfo.topActivityInfo;
         final int themeBGColor = legacyDrawable != null
                 ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable))
                 : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs));
@@ -258,6 +262,7 @@
                 .overlayDrawable(legacyDrawable)
                 .chooseStyle(suggestType)
                 .setUiThreadInitConsumer(uiThreadInitConsumer)
+                .setAllowHandleEmpty(info.allowHandleEmptySplashScreen())
                 .build();
     }
 
@@ -327,6 +332,7 @@
         private Drawable[] mFinalIconDrawables;
         private int mFinalIconSize = mIconSize;
         private Consumer<Runnable> mUiThreadInitTask;
+        private boolean mAllowHandleEmpty;
 
         StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
             mContext = context;
@@ -353,6 +359,11 @@
             return this;
         }
 
+        StartingWindowViewBuilder setAllowHandleEmpty(boolean allowHandleEmpty) {
+            mAllowHandleEmpty = allowHandleEmpty;
+            return this;
+        }
+
         SplashScreenView build() {
             Drawable iconDrawable;
             final int animationDuration;
@@ -491,7 +502,8 @@
                     .setIconBackground(background)
                     .setCenterViewDrawable(foreground)
                     .setAnimationDurationMillis(animationDuration)
-                    .setUiThreadInitConsumer(uiThreadInitTask);
+                    .setUiThreadInitConsumer(uiThreadInitTask)
+                    .setAllowHandleEmpty(mAllowHandleEmpty);
 
             if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
                     && mTmpAttrs.mBrandingImage != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index f8902c6..9a966b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -328,7 +328,7 @@
         if (mSysuiProxy != null) {
             mSysuiProxy.requestTopUi(true, TAG);
         }
-        mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId,
+        mSplashscreenContentDrawer.createContentView(context, suggestType, windowInfo,
                 viewSupplier::setView, viewSupplier::setUiThreadInitTask);
         try {
             if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
index f8d14c6..af629cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
@@ -24,9 +24,6 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.helpers.BaseAppHelper
-import org.junit.Assume
-import org.junit.Before
 import org.junit.runner.RunWith
 import org.junit.Test
 import org.junit.runners.Parameterized
@@ -62,12 +59,6 @@
             }
         }
 
-    @Before
-    fun setup() {
-        // This test doesn't work in shell transitions because of b/205288792
-        Assume.assumeFalse(BaseAppHelper.isShellTransitionsEnabled())
-    }
-
     @Presubmit
     @Test
     fun testAppIsAlwaysVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
index c93c5ad..add11c1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -25,9 +25,6 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.helpers.BaseAppHelper
-import org.junit.Assume
-import org.junit.Before
 import org.junit.runner.RunWith
 import org.junit.Test
 import org.junit.runners.Parameterized
@@ -70,12 +67,6 @@
             }
         }
 
-    @Before
-    fun setup() {
-        // This test doesn't work in shell transitions because of b/205288792
-        Assume.assumeFalse(BaseAppHelper.isShellTransitionsEnabled())
-    }
-
     @Presubmit
     @Test
     fun testAppIsAlwaysVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index dee13c1..afe64e3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -204,7 +204,6 @@
     @Presubmit
     @Test
     fun testAppPlusPipLayerCoversFullScreenOnEnd() {
-        // This test doesn't work in shell transitions because of b/206669574
         testSpec.assertLayersEnd {
             val pipRegion = visibleRegion(pipApp.component).region
             visibleRegion(testApp.component)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index c36dfda..1d61ab4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -31,6 +31,7 @@
 import com.android.server.wm.traces.common.FlickerComponentName
 import com.android.wm.shell.flicker.helpers.ImeAppHelper
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -82,6 +83,13 @@
         super.statusBarLayerRotatesScales()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun statusBarLayerRotatesScales_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.statusBarLayerRotatesScales()
+    }
+
     /**
      * Ensure the pip window remains visible throughout any keyboard interactions
      */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index df58194..21175a0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -92,11 +92,7 @@
     /** {@inheritDoc}  */
     @FlakyTest(bugId = 206753786)
     @Test
-    override fun statusBarLayerRotatesScales() {
-        // This test doesn't work in shell transitions because of b/206753786
-        assumeFalse(com.android.server.wm.flicker.helpers.isShellTransitionsEnabled)
-        super.statusBarLayerRotatesScales()
-    }
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
 
     @FlakyTest(bugId = 161435597)
     @Test
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 6989ac0..5db0783 100755
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -686,16 +686,14 @@
                                           }
                                           return data->ptr != nullptr;
                                       }));
-        inPlaceCallback(std::move(data.ptr), data.size);
-        return STATUS_OK;
+        return inPlaceCallback(std::move(data.ptr), data.size);
     } else if (type == BlobType::ASHMEM) {
         int rawFd = -1;
         int32_t size = 0;
         ON_ERROR_RETURN(AParcel_readInt32(parcel, &size));
         ON_ERROR_RETURN(AParcel_readParcelFileDescriptor(parcel, &rawFd));
         android::base::unique_fd fd(rawFd);
-        ashmemCallback(std::move(fd), size);
-        return STATUS_OK;
+        return ashmemCallback(std::move(fd), size);
     } else {
         // Although the above if/else was "exhaustive" guard against unknown types
         return STATUS_UNKNOWN_ERROR;
@@ -768,7 +766,7 @@
 // framework, we may need to update this maximum size.
 static constexpr size_t kMaxColorSpaceSerializedBytes = 80;
 
-static constexpr auto RuntimeException = "java/lang/RuntimeException";
+static constexpr auto BadParcelableException = "android/os/BadParcelableException";
 
 static bool validateImageInfo(const SkImageInfo& info, int32_t rowBytes) {
     // TODO: Can we avoid making a SkBitmap for this?
@@ -809,7 +807,7 @@
             kRGB_565_SkColorType != colorType &&
             kARGB_4444_SkColorType != colorType &&
             kAlpha_8_SkColorType != colorType) {
-        jniThrowExceptionFmt(env, RuntimeException,
+        jniThrowExceptionFmt(env, BadParcelableException,
                              "Bitmap_createFromParcel unknown colortype: %d\n", colorType);
         return NULL;
     }
@@ -821,7 +819,7 @@
         return NULL;
     }
     if (!Bitmap::computeAllocationSize(rowBytes, height, &allocationSize)) {
-        jniThrowExceptionFmt(env, RuntimeException,
+        jniThrowExceptionFmt(env, BadParcelableException,
                              "Received bad bitmap size: width=%d, height=%d, rowBytes=%d", width,
                              height, rowBytes);
         return NULL;
@@ -831,13 +829,23 @@
             p.get(),
             // In place callback
             [&](std::unique_ptr<int8_t[]> buffer, int32_t size) {
+                if (allocationSize > size) {
+                    android_errorWriteLog(0x534e4554, "213169612");
+                    return STATUS_BAD_VALUE;
+                }
                 nativeBitmap = Bitmap::allocateHeapBitmap(allocationSize, imageInfo, rowBytes);
                 if (nativeBitmap) {
-                    memcpy(nativeBitmap->pixels(), buffer.get(), size);
+                    memcpy(nativeBitmap->pixels(), buffer.get(), allocationSize);
+                    return STATUS_OK;
                 }
+                return STATUS_NO_MEMORY;
             },
             // Ashmem callback
             [&](android::base::unique_fd fd, int32_t size) {
+                if (allocationSize > size) {
+                    android_errorWriteLog(0x534e4554, "213169612");
+                    return STATUS_BAD_VALUE;
+                }
                 int flags = PROT_READ;
                 if (isMutable) {
                     flags |= PROT_WRITE;
@@ -846,18 +854,21 @@
                 if (addr == MAP_FAILED) {
                     const int err = errno;
                     ALOGW("mmap failed, error %d (%s)", err, strerror(err));
-                    return;
+                    return STATUS_NO_MEMORY;
                 }
                 nativeBitmap =
                         Bitmap::createFrom(imageInfo, rowBytes, fd.release(), addr, size, !isMutable);
+                return STATUS_OK;
             });
-    if (error != STATUS_OK) {
+
+    if (error != STATUS_OK && error != STATUS_NO_MEMORY) {
         // TODO: Stringify the error, see signalExceptionForError in android_util_Binder.cpp
-        jniThrowExceptionFmt(env, RuntimeException, "Failed to read from Parcel, error=%d", error);
+        jniThrowExceptionFmt(env, BadParcelableException, "Failed to read from Parcel, error=%d",
+                             error);
         return nullptr;
     }
-    if (!nativeBitmap) {
-        jniThrowRuntimeException(env, "Could not allocate java pixel ref.");
+    if (error == STATUS_NO_MEMORY || !nativeBitmap) {
+        jniThrowRuntimeException(env, "Could not allocate bitmap data.");
         return nullptr;
     }
 
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 09d7fbd..e2e48d3 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -963,7 +963,7 @@
          *
          * @see HardwareBuffer
          */
-        public @NonNull Builder setUsage(long usage) {
+        public @NonNull Builder setUsage(@Usage long usage) {
             mUsage = usage;
             return this;
         }
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 6168c22..a1aedf1 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -102,11 +102,10 @@
     private int mWidth;
     private int mHeight;
     private final int mMaxImages;
-    private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
+    private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
     private @HardwareBuffer.Format int mHardwareBufferFormat;
     private @NamedDataSpace long mDataSpace;
     private boolean mUseLegacyImageFormat;
-    private boolean mUseSurfaceImageFormatInfo;
 
     // Field below is used by native code, do not access or modify.
     private int mWriterFormat;
@@ -255,35 +254,38 @@
                 + ", maxImages: " + maxImages);
         }
 
-        mUseSurfaceImageFormatInfo = useSurfaceImageFormatInfo;
         mUseLegacyImageFormat = useLegacyImageFormat;
         // Note that the underlying BufferQueue is working in synchronous mode
         // to avoid dropping any buffers.
         mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height,
             useSurfaceImageFormatInfo, hardwareBufferFormat, dataSpace, usage);
 
+        // if useSurfaceImageFormatInfo is true, imageformat should be read from the surface.
         if (useSurfaceImageFormatInfo) {
             // nativeInit internally overrides UNKNOWN format. So does surface format query after
             // nativeInit and before getEstimatedNativeAllocBytes().
             imageFormat = SurfaceUtils.getSurfaceFormat(surface);
-            // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
-            // allocation estimation sequence depends on the public formats values. To avoid
-            // possible errors, convert where necessary.
-            if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
-                int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
-                switch (surfaceDataspace) {
-                    case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
-                        imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
-                        break;
-                    case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
-                        imageFormat = ImageFormat.DEPTH_JPEG;
-                        break;
-                    case StreamConfigurationMap.HAL_DATASPACE_HEIF:
-                        imageFormat = ImageFormat.HEIC;
-                        break;
-                    default:
-                        imageFormat = ImageFormat.JPEG;
-                }
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
+
+        // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
+        // allocation estimation sequence depends on the public formats values. To avoid
+        // possible errors, convert where necessary.
+        if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
+            int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
+            switch (surfaceDataspace) {
+                case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
+                    imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
+                    break;
+                case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
+                    imageFormat = ImageFormat.DEPTH_JPEG;
+                    break;
+                case StreamConfigurationMap.HAL_DATASPACE_HEIF:
+                    imageFormat = ImageFormat.HEIC;
+                    break;
+                default:
+                    imageFormat = ImageFormat.JPEG;
             }
             mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
             mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
@@ -307,7 +309,6 @@
     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
             int imageFormat, int width, int height) {
         mMaxImages = maxImages;
-        // update hal format and dataspace only if image format is overridden by producer.
         mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
         mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
 
@@ -566,6 +567,9 @@
     /**
      * Get the ImageWriter usage flag.
      *
+     * <p>It is not recommended to use this function if {@link Builder#setUsage} is not called.
+     * Invalid usage value will be returned if so.</p>
+     *
      * @return The ImageWriter usage flag.
      */
     public @Usage long getUsage() {
@@ -873,7 +877,7 @@
         private int mHeight = -1;
         private int mMaxImages = 1;
         private int mImageFormat = ImageFormat.UNKNOWN;
-        private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
+        private long mUsage = -1;
         private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
         private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
         private boolean mUseSurfaceImageFormatInfo = true;
@@ -885,10 +889,19 @@
         /**
          * Constructs a new builder for {@link ImageWriter}.
          *
+         * <p>Uses {@code surface} input parameter to retrieve image format, hal format
+         * and hal dataspace value for default. </p>
+         *
          * @param surface The destination Surface this writer produces Image data into.
+         *
+         * @throws IllegalArgumentException if the surface is already abandoned.
          */
         public Builder(@NonNull Surface surface) {
             mSurface = surface;
+            // retrieve format from surface
+            mImageFormat = SurfaceUtils.getSurfaceFormat(surface);
+            mDataSpace = SurfaceUtils.getSurfaceDataspace(surface);
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mImageFormat);
         }
 
         /**
@@ -926,6 +939,8 @@
          * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified
          *                    by {@link ImageFormat} or {@link PixelFormat}.
          * @return the Builder instance with customized image format.
+         *
+         * @throws IllegalArgumentException if {@code imageFormat} is invalid.
          */
         @SuppressLint("MissingGetterMatchingBuilder")
         public @NonNull Builder setImageFormat(@Format int imageFormat) {
@@ -985,12 +1000,16 @@
 
         /**
          * Set the usage flag of this ImageWriter.
-         * Default value is {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN}.
+         *
+         * <p>If this function is not called, usage bit will be set
+         * to {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} if the image format is not
+         * {@link ImageFormat#PRIVATE PRIVATE}.</p>
          *
          * @param usage The intended usage of the images produced by this ImageWriter.
          * @return the Builder instance with customized usage flag.
          *
          * @see HardwareBuffer
+         * @see #getUsage
          */
         public @NonNull Builder setUsage(@Usage long usage) {
             mUsage = usage;
@@ -1022,6 +1041,7 @@
         private int mHeight = -1;
         private int mWidth = -1;
         private int mFormat = -1;
+        private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
         // When this default timestamp is used, timestamp for the input Image
         // will be generated automatically when queueInputBuffer is called.
         private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE;
@@ -1034,19 +1054,34 @@
             mOwner = writer;
             mWidth = writer.mWidth;
             mHeight = writer.mHeight;
+            mDataSpace = writer.mDataSpace;
 
-            if (!writer.mUseLegacyImageFormat) {
+            if (!mOwner.mUseLegacyImageFormat) {
                 mFormat = PublicFormatUtils.getPublicFormat(
-                        writer.mHardwareBufferFormat, writer.mDataSpace);
+                    mOwner.mHardwareBufferFormat, mDataSpace);
             }
         }
 
         @Override
+        public @NamedDataSpace long getDataSpace() {
+            throwISEIfImageIsInvalid();
+
+            return mDataSpace;
+        }
+
+        @Override
+        public void setDataSpace(@NamedDataSpace long dataSpace) {
+            throwISEIfImageIsInvalid();
+
+            mDataSpace = dataSpace;
+        }
+
+        @Override
         public int getFormat() {
             throwISEIfImageIsInvalid();
 
-            if (mFormat == -1) {
-                mFormat = nativeGetFormat();
+            if (mOwner.mUseLegacyImageFormat && mFormat == -1) {
+                mFormat = nativeGetFormat(mDataSpace);
             }
             return mFormat;
         }
@@ -1114,7 +1149,8 @@
 
             if (mPlanes == null) {
                 int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat());
-                mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat());
+                mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat(),
+                        getOwner().getDataSpace());
             }
 
             return mPlanes.clone();
@@ -1222,13 +1258,14 @@
         }
 
         // Create the SurfacePlane object and fill the information
-        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);
+        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt,
+                long dataSpace);
 
         private synchronized native int nativeGetWidth();
 
         private synchronized native int nativeGetHeight();
 
-        private synchronized native int nativeGetFormat();
+        private synchronized native int nativeGetFormat(long dataSpace);
 
         private synchronized native HardwareBuffer nativeGetHardwareBuffer();
     }
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index e75df1d..3fd27d5 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -426,10 +426,30 @@
         /** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
         public static final int COLOR_Format24BitABGR6666           = 43;
 
-        /** @hide
-         * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
-         * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
-         * little-endian value, with the lower 6 bits set to zero. */
+        /**
+         * P010 is 10-bit-per component 4:2:0 YCbCr semiplanar format.
+         * <p>
+         * This format uses 24 allocated bits per pixel with 15 bits of
+         * data per pixel. Chroma planes are subsampled by 2 both
+         * horizontally and vertically. Each chroma and luma component
+         * has 16 allocated bits in little-endian configuration with 10
+         * MSB of actual data.
+         *
+         * <pre>
+         *            byte                   byte
+         *  <--------- i --------> | <------ i + 1 ------>
+         * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+         * |     UNUSED      |      Y/Cb/Cr                |
+         * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+         *  0               5 6   7 0                    7
+         * bit
+         * </pre>
+         *
+         * Use this format with {@link Image}. This format corresponds
+         * to {@link android.graphics.ImageFormat#YCBCR_P010}.
+         * <p>
+         */
+        @SuppressLint("AllUpper")
         public static final int COLOR_FormatYUVP010                 = 54;
 
         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
@@ -615,6 +635,24 @@
         public static final String FEATURE_EncodingStatistics = "encoding-statistics";
 
         /**
+         * <b>video encoder only</b>: codec supports HDR editing.
+         * <p>
+         * HDR editing support means that the codec accepts 10-bit HDR
+         * input surface, and it is capable of generating any HDR
+         * metadata required from both YUV and RGB input when the
+         * metadata is not present. This feature is only meaningful when
+         * using an HDR capable profile (and 10-bit HDR input).
+         * <p>
+         * This feature implies that the codec is capable of encoding at
+         * least one HDR format, and that it supports RGBA_1010102 as
+         * well as P010, and optionally RGBA_FP16 input formats, and
+         * that the encoder can generate HDR metadata for all supported
+         * HDR input formats.
+         */
+        @SuppressLint("AllUpper")
+        public static final String FEATURE_HdrEditing = "hdr-editing";
+
+        /**
          * Query codec feature capabilities.
          * <p>
          * These features are supported to be used by the codec.  These
@@ -654,6 +692,7 @@
             new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
             new Feature(FEATURE_QpBounds, (1 << 3), false),
             new Feature(FEATURE_EncodingStatistics, (1 << 4), false),
+            new Feature(FEATURE_HdrEditing, (1 << 5), false),
             // feature to exclude codec from REGULAR codec list
             new Feature(FEATURE_SpecialCodec,     (1 << 30), false, true),
         };
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index ad8fc07..ea26185 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -1078,8 +1078,8 @@
      *
      * @throws IOException When an {@link IOException} is thrown while closing a {@link
      * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}. This throws clause exists
-     * since API 33, but this method can throw in earlier API versions where the exception is not
-     * declared.
+     * since API {@link android.os.Build.VERSION_CODES#TIRAMISU}, but this method can throw in
+     * earlier API versions where the exception is not declared.
      */
     @Override
     public void close() throws IOException {
@@ -1091,8 +1091,8 @@
      *
      * @throws IOException When an {@link IOException} is thrown while closing a {@link
      * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}. This throws clause exists
-     * since API 33, but this method can throw in earlier API versions where the exception is not
-     * declared.
+     * since API {@link android.os.Build.VERSION_CODES#TIRAMISU}, but this method can throw in
+     * earlier API versions where the exception is not declared.
      */
     public native void release() throws IOException;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index a6f244f..2772769 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -1059,7 +1059,8 @@
      * haptic channels or not. As this function doesn't has a context
      * to resolve the uri, the result may be wrong if the uri cannot be
      * resolved correctly.
-     * Use {@link #hasHapticChannels(int)} instead when possible.
+     * Use {@link #hasHapticChannels(int)} or {@link #hasHapticChannels(Context, Uri)}
+     * instead when possible.
      *
      * @param ringtoneUri The {@link Uri} of a sound or ringtone.
      * @return true if the ringtone contains haptic channels.
@@ -1069,6 +1070,17 @@
     }
 
     /**
+     * Returns if the {@link Ringtone} from a given sound URI contains haptics channels or not.
+     *
+     * @param context the {@link android.content.Context} to use when resolving the Uri.
+     * @param ringtoneUri the {@link Uri} of a sound or ringtone.
+     * @return true if the ringtone contains haptic channels.
+     */
+    public static boolean hasHapticChannels(@NonNull Context context, @NonNull Uri ringtoneUri) {
+        return AudioManager.hasHapticChannels(context, ringtoneUri);
+    }
+
+    /**
      * Attempts to create a context for the given user.
      *
      * @return created context, or null if package does not exist
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
index 536baf2..0542c55 100644
--- a/media/java/android/media/tv/AdRequest.java
+++ b/media/java/android/media/tv/AdRequest.java
@@ -16,8 +16,9 @@
 
 package android.media.tv;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.StringDef;
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
@@ -26,17 +27,26 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-/** @hide */
+/**
+ * An advertisement request which can be sent to TV input to request AD operations.
+ */
 public final class AdRequest implements Parcelable {
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef(prefix = "REQUEST_TYPE_", value = {
+    @IntDef(prefix = "REQUEST_TYPE_", value = {
             REQUEST_TYPE_START,
             REQUEST_TYPE_STOP
     })
     public @interface RequestType {}
 
-    public static final String REQUEST_TYPE_START = "START";
-    public static final String REQUEST_TYPE_STOP = "STOP";
+    /**
+     * Request to start an advertisement.
+     */
+    public static final int REQUEST_TYPE_START = 1;
+    /**
+     * Request to stop an advertisement.
+     */
+    public static final int REQUEST_TYPE_STOP = 2;
 
     public static final @NonNull Parcelable.Creator<AdRequest> CREATOR =
             new Parcelable.Creator<AdRequest>() {
@@ -52,7 +62,7 @@
             };
 
     private final int mId;
-    private final @RequestType String mRequestType;
+    private final @RequestType int mRequestType;
     private final ParcelFileDescriptor mFileDescriptor;
     private final long mStartTime;
     private final long mStopTime;
@@ -60,9 +70,9 @@
     private final String mMediaFileType;
     private final Bundle mMetadata;
 
-    public AdRequest(int id, @RequestType String requestType, ParcelFileDescriptor fileDescriptor,
-            long startTime, long stopTime, long echoInterval, String mediaFileType,
-            Bundle metadata) {
+    public AdRequest(int id, @RequestType int requestType,
+            @Nullable ParcelFileDescriptor fileDescriptor, long startTime, long stopTime,
+            long echoInterval, @Nullable String mediaFileType, @NonNull Bundle metadata) {
         mId = id;
         mRequestType = requestType;
         mFileDescriptor = fileDescriptor;
@@ -75,8 +85,12 @@
 
     private AdRequest(Parcel source) {
         mId = source.readInt();
-        mRequestType = source.readString();
-        mFileDescriptor = source.readFileDescriptor();
+        mRequestType = source.readInt();
+        if (source.readInt() != 0) {
+            mFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(source);
+        } else {
+            mFileDescriptor = null;
+        }
         mStartTime = source.readLong();
         mStopTime = source.readLong();
         mEchoInterval = source.readLong();
@@ -84,34 +98,77 @@
         mMetadata = source.readBundle();
     }
 
+    /**
+     * Gets the ID of AD request.
+     */
     public int getId() {
         return mId;
     }
 
-    public @RequestType String getRequestType() {
+    /**
+     * Gets the request type.
+     */
+    @RequestType
+    public int getRequestType() {
         return mRequestType;
     }
 
+    /**
+     * Gets the file descriptor of the AD media.
+     *
+     * @return The file descriptor of the AD media. Can be {@code null} for
+     *         {@link #REQUEST_TYPE_STOP}
+     */
+    @Nullable
     public ParcelFileDescriptor getFileDescriptor() {
         return mFileDescriptor;
     }
 
-    public long getStartTime() {
+    /**
+     * Gets the start time of the AD media in milliseconds.
+     * <p>0 means start immediately
+     */
+    public long getStartTimeMillis() {
         return mStartTime;
     }
 
-    public long getStopTime() {
+    /**
+     * Gets the stop time of the AD media in milliseconds.
+     * <p>-1 means until the end
+     */
+    public long getStopTimeMillis() {
         return mStopTime;
     }
 
-    public long getEchoInterval() {
+    /**
+     * Gets the echo interval in milliseconds.
+     * <p>The interval TV input needs to echo and inform TV interactive app service the video
+     * playback elapsed time.
+     *
+     * @see android.media.tv.AdResponse
+     */
+    public long getEchoIntervalMillis() {
         return mEchoInterval;
     }
 
+    /**
+     * Gets the media file type such as mp4, mob, avi.
+     *
+     * @return The media file type. Can be {@code null} for {@link #REQUEST_TYPE_STOP}.
+     */
+    @Nullable
     public String getMediaFileType() {
         return mMediaFileType;
     }
 
+    /**
+     * Gets the metadata of the media file.
+     * <p>This includes additional information the TV input needs to play the AD media.
+     *
+     * @return The metadata of the media file. Can be an empty bundle for
+     *         {@link #REQUEST_TYPE_STOP}.
+     */
+    @NonNull
     public Bundle getMetadata() {
         return mMetadata;
     }
@@ -124,8 +181,13 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mId);
-        dest.writeString(mRequestType);
-        mFileDescriptor.writeToParcel(dest, flags);
+        dest.writeInt(mRequestType);
+        if (mFileDescriptor != null) {
+            dest.writeInt(1);
+            mFileDescriptor.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
         dest.writeLong(mStartTime);
         dest.writeLong(mStopTime);
         dest.writeLong(mEchoInterval);
diff --git a/media/java/android/media/tv/AdResponse.java b/media/java/android/media/tv/AdResponse.java
index 28cf5ac..0c20954 100644
--- a/media/java/android/media/tv/AdResponse.java
+++ b/media/java/android/media/tv/AdResponse.java
@@ -16,19 +16,21 @@
 
 package android.media.tv;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-/** @hide */
+/**
+ * An advertisement request which can be sent to TV interactive App service to inform AD status.
+ */
 public final class AdResponse implements Parcelable {
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef(prefix = "RESPONSE_TYPE_", value = {
+    @IntDef(prefix = "RESPONSE_TYPE_", value = {
             RESPONSE_TYPE_PLAYING,
             RESPONSE_TYPE_FINISHED,
             RESPONSE_TYPE_STOPPED,
@@ -36,10 +38,10 @@
     })
     public @interface ResponseType {}
 
-    public static final String RESPONSE_TYPE_PLAYING = "PLAYING";
-    public static final String RESPONSE_TYPE_FINISHED = "FINISHED";
-    public static final String RESPONSE_TYPE_STOPPED = "STOPPED";
-    public static final String RESPONSE_TYPE_ERROR = "ERROR";
+    public static final int RESPONSE_TYPE_PLAYING = 1;
+    public static final int RESPONSE_TYPE_FINISHED = 2;
+    public static final int RESPONSE_TYPE_STOPPED = 3;
+    public static final int RESPONSE_TYPE_ERROR = 4;
 
     public static final @NonNull Parcelable.Creator<AdResponse> CREATOR =
             new Parcelable.Creator<AdResponse>() {
@@ -55,10 +57,10 @@
             };
 
     private final int mId;
-    private final @ResponseType String mResponseType;
-    private final Long mElapsedTime;
+    private final @ResponseType int mResponseType;
+    private final long mElapsedTime;
 
-    public AdResponse(int id, @ResponseType String responseType, @Nullable Long elapsedTime) {
+    public AdResponse(int id, @ResponseType int responseType, long elapsedTime) {
         mId = id;
         mResponseType = responseType;
         mElapsedTime = elapsedTime;
@@ -66,19 +68,31 @@
 
     private AdResponse(Parcel source) {
         mId = source.readInt();
-        mResponseType = source.readString();
-        mElapsedTime = (Long) source.readValue(Long.class.getClassLoader());
+        mResponseType = source.readInt();
+        mElapsedTime = source.readLong();
     }
 
+    /**
+     * Gets the ID of AD response.
+     */
     public int getId() {
         return mId;
     }
 
-    public @ResponseType String getResponseType() {
+    /**
+     * Gets the response type.
+     */
+    @ResponseType
+    public int getResponseType() {
         return mResponseType;
     }
 
-    public Long getElapsedTime() {
+    /**
+     * Gets the playback elapsed time in milliseconds.
+     *
+     * @return The playback elapsed time. -1 if no valid elapsed time.
+     */
+    public long getElapsedTimeMillis() {
         return mElapsedTime;
     }
 
@@ -90,7 +104,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mId);
-        dest.writeString(mResponseType);
-        dest.writeValue(mElapsedTime);
+        dest.writeInt(mResponseType);
+        dest.writeLong(mElapsedTime);
     }
 }
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f438d29..cc33a1e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -394,17 +394,14 @@
 
     /**
      * Signal lost.
-     * @hide
      */
     public static final int SIGNAL_STRENGTH_LOST = 1;
     /**
      * Weak signal.
-     * @hide
      */
     public static final int SIGNAL_STRENGTH_WEAK = 2;
     /**
      * Strong signal.
-     * @hide
      */
     public static final int SIGNAL_STRENGTH_STRONG = 3;
 
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 1a9cab0..f63f444 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -895,7 +895,7 @@
          * Notifies response for advertisement.
          *
          * @param response advertisement response.
-         * @hide
+         * @see android.media.tv.interactive.TvInteractiveAppService.Session#requestAd(AdRequest)
          */
         public void notifyAdResponse(@NonNull final AdResponse response) {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -976,7 +976,6 @@
 
         /**
          * Notifies signal strength.
-         * @hide
          */
         public void notifySignalStrength(@TvInputManager.SignalStrength final int strength) {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1124,10 +1123,9 @@
         }
 
         /**
-         * called when advertisement is requested.
+         * Called when advertisement request is received.
          *
-         * @param request advertisement request
-         * @hide
+         * @param request advertisement request received
          */
         public void onRequestAd(@NonNull AdRequest request) {
         }
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 6c25a70..4d63af7 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -1079,21 +1079,20 @@
 
         /**
          * This is called when signal strength is updated.
+         *
          * @param inputId The ID of the TV input bound to this view.
          * @param strength The current signal strength.
-         *
-         * @hide
          */
-        public void onSignalStrength(String inputId, @TvInputManager.SignalStrength int strength) {
+        public void onSignalStrength(
+                @NonNull String inputId, @TvInputManager.SignalStrength int strength) {
         }
 
         /**
          * This is called when the session has been tuned to the given channel.
          *
          * @param channelUri The URI of a channel.
-         * @hide
          */
-        public void onTuned(String inputId, Uri channelUri) {
+        public void onTuned(@NonNull String inputId, @NonNull Uri channelUri) {
         }
     }
 
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index c5dfaa2..4a99715 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -28,6 +28,7 @@
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
 import android.media.tv.TvContentRating;
+import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
@@ -173,18 +174,15 @@
     public @interface TeletextAppState {}
 
     /**
-     * Show state of Teletext app.
-     * @hide
+     * State of Teletext app: show
      */
     public static final int TELETEXT_APP_STATE_SHOW = 1;
     /**
-     * Hide state of Teletext app.
-     * @hide
+     * State of Teletext app: hide
      */
     public static final int TELETEXT_APP_STATE_HIDE = 2;
     /**
-     * Error state of Teletext app.
-     * @hide
+     * State of Teletext app: error
      */
     public static final int TELETEXT_APP_STATE_ERROR = 3;
 
@@ -192,9 +190,7 @@
      * Key for package name in app link.
      * <p>Type: String
      *
-     * @see #registerAppLinkInfo(String, Bundle)
      * @see #sendAppLinkCommand(String, Bundle)
-     * @hide
      */
     public static final String KEY_PACKAGE_NAME = "package_name";
 
@@ -202,45 +198,15 @@
      * Key for class name in app link.
      * <p>Type: String
      *
-     * @see #registerAppLinkInfo(String, Bundle)
      * @see #sendAppLinkCommand(String, Bundle)
-     * @hide
      */
     public static final String KEY_CLASS_NAME = "class_name";
 
     /**
-     * Key for URI scheme in app link.
-     * <p>Type: String
-     *
-     * @see #registerAppLinkInfo(String, Bundle)
-     * @hide
-     */
-    public static final String KEY_URI_SCHEME = "uri_scheme";
-
-    /**
-     * Key for URI host in app link.
-     * <p>Type: String
-     *
-     * @see #registerAppLinkInfo(String, Bundle)
-     * @hide
-     */
-    public static final String KEY_URI_HOST = "uri_host";
-
-    /**
-     * Key for URI prefix in app link.
-     * <p>Type: String
-     *
-     * @see #registerAppLinkInfo(String, Bundle)
-     * @hide
-     */
-    public static final String KEY_URI_PREFIX = "uri_prefix";
-
-    /**
      * Key for command type in app link command.
      * <p>Type: String
      *
      * @see #sendAppLinkCommand(String, Bundle)
-     * @hide
      */
     public static final String KEY_COMMAND_TYPE = "command_type";
 
@@ -249,7 +215,6 @@
      * <p>Type: String
      *
      * @see #sendAppLinkCommand(String, Bundle)
-     * @hide
      */
     public static final String KEY_SERVICE_ID = "service_id";
 
@@ -258,10 +223,68 @@
      * <p>Type: String
      *
      * @see #sendAppLinkCommand(String, Bundle)
-     * @hide
      */
     public static final String KEY_BACK_URI = "back_uri";
 
+    /**
+     * Broadcast intent action to send app command to TV app.
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     */
+    public static final String ACTION_APP_LINK_COMMAND =
+            "android.media.tv.interactive.action.APP_LINK_COMMAND";
+
+    /**
+     * Intent key for TV input ID. It's used to send app command to TV app.
+     * <p>Type: String
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     * @see #ACTION_APP_LINK_COMMAND
+     */
+    public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id";
+
+    /**
+     * Intent key for TV interactive app ID. It's used to send app command to TV app.
+     * <p>Type: String
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     * @see #ACTION_APP_LINK_COMMAND
+     * @see android.media.tv.interactive.TvInteractiveAppInfo#getId()
+     */
+    public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
+
+    /**
+     * Intent key for TV channel URI. It's used to send app command to TV app.
+     * <p>Type: android.net.Uri
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     * @see #ACTION_APP_LINK_COMMAND
+     */
+    public static final String INTENT_KEY_CHANNEL_URI = "channel_uri";
+
+    /**
+     * Intent key for broadcast-independent(BI) interactive app type. It's used to send app command
+     * to TV app.
+     * <p>Type: int
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     * @see #ACTION_APP_LINK_COMMAND
+     * @see android.media.tv.interactive.TvInteractiveAppInfo#getSupportedTypes()
+     * @see android.media.tv.interactive.TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+     */
+    public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
+
+    /**
+     * Intent key for broadcast-independent(BI) interactive app URI. It's used to send app command
+     * to TV app.
+     * <p>Type: android.net.Uri
+     *
+     * @see #sendAppLinkCommand(String, Bundle)
+     * @see #ACTION_APP_LINK_COMMAND
+     * @see android.media.tv.interactive.TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+     */
+    public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
+
     private final ITvInteractiveAppManager mService;
     private final int mUserId;
 
@@ -357,7 +380,7 @@
 
             @Override
             public void onCommandRequest(
-                    @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
+                    @TvInteractiveAppService.PlaybackCommandType String cmdType,
                     Bundle parameters,
                     int seq) {
                 synchronized (mSessionCallbackRecordMap) {
@@ -558,7 +581,6 @@
          * that implements {@link TvInteractiveAppService} interface.
          *
          * @param iAppServiceId The ID of the TV Interactive App service.
-         * @hide
          */
         public void onInteractiveAppServiceAdded(@NonNull String iAppServiceId) {
         }
@@ -570,7 +592,6 @@
          * App service package.
          *
          * @param iAppServiceId The ID of the TV Interactive App service.
-         * @hide
          */
         public void onInteractiveAppServiceRemoved(@NonNull String iAppServiceId) {
         }
@@ -582,7 +603,6 @@
          * re-installed or a newer version of the package exists becomes available/unavailable.
          *
          * @param iAppServiceId The ID of the TV Interactive App service.
-         * @hide
          */
         public void onInteractiveAppServiceUpdated(@NonNull String iAppServiceId) {
         }
@@ -729,8 +749,7 @@
     }
 
     /**
-     * Prepares TV Interactive App service for the given type.
-     * @hide
+     * Prepares TV Interactive App service environment for the given type.
      */
     public void prepare(@NonNull String tvIAppServiceId, int type) {
         try {
@@ -768,9 +787,12 @@
 
     /**
      * Sends app link command.
-     * @hide
+     *
+     * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+     *                        ID can be found in {@link TvInputInfo#getId()}.
+     * @param command The command to be sent.
      */
-    public void sendAppLinkCommand(String tvIAppServiceId, Bundle command) {
+    public void sendAppLinkCommand(@NonNull String tvIAppServiceId, @NonNull Bundle command) {
         try {
             mService.sendAppLinkCommand(tvIAppServiceId, command, mUserId);
         } catch (RemoteException e) {
@@ -1560,7 +1582,7 @@
         }
 
         void postCommandRequest(
-                final @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
+                final @TvInteractiveAppService.PlaybackCommandType String cmdType,
                 final Bundle parameters) {
             mHandler.post(new Runnable() {
                 @Override
@@ -1708,7 +1730,7 @@
          */
         public void onCommandRequest(
                 Session session,
-                @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
+                @TvInteractiveAppService.PlaybackCommandType String cmdType,
                 Bundle parameters) {
         }
 
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index afa1ff7..c9856bf 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -32,6 +32,7 @@
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.BroadcastInfoResponse;
 import android.media.tv.TvContentRating;
+import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvTrackInfo;
 import android.media.tv.TvView;
@@ -97,46 +98,82 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @StringDef(prefix = "INTERACTIVE_APP_SERVICE_COMMAND_TYPE_", value = {
-            INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE,
-            INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_NEXT,
-            INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_PREV,
-            INTERACTIVE_APP_SERVICE_COMMAND_TYPE_STOP,
-            INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME,
-            INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SELECT_TRACK
+    @StringDef(prefix = "PLAYBACK_COMMAND_TYPE_", value = {
+            PLAYBACK_COMMAND_TYPE_TUNE,
+            PLAYBACK_COMMAND_TYPE_TUNE_NEXT,
+            PLAYBACK_COMMAND_TYPE_TUNE_PREV,
+            PLAYBACK_COMMAND_TYPE_STOP,
+            PLAYBACK_COMMAND_TYPE_SET_STREAM_VOLUME,
+            PLAYBACK_COMMAND_TYPE_SELECT_TRACK
     })
-    public @interface InteractiveAppServiceCommandType {}
+    public @interface PlaybackCommandType {}
 
-    /** @hide */
-    public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE = "tune";
-    /** @hide */
-    public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_NEXT = "tune_next";
-    /** @hide */
-    public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_PREV = "tune_previous";
-    /** @hide */
-    public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_STOP = "stop";
-    /** @hide */
-    public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME =
+    /**
+     * Playback command type: tune to the given channel.
+     * @see #COMMAND_PARAMETER_KEY_CHANNEL_URI
+     */
+    public static final String PLAYBACK_COMMAND_TYPE_TUNE = "tune";
+    /**
+     * Playback command type: tune to the next channel.
+     */
+    public static final String PLAYBACK_COMMAND_TYPE_TUNE_NEXT = "tune_next";
+    /**
+     * Playback command type: tune to the previous channel.
+     */
+    public static final String PLAYBACK_COMMAND_TYPE_TUNE_PREV = "tune_previous";
+    /**
+     * Playback command type: stop the playback.
+     */
+    public static final String PLAYBACK_COMMAND_TYPE_STOP = "stop";
+    /**
+     * Playback command type: set the volume.
+     */
+    public static final String PLAYBACK_COMMAND_TYPE_SET_STREAM_VOLUME =
             "set_stream_volume";
-    /** @hide */
-    public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SELECT_TRACK = "select_track";
-    /** @hide */
+    /**
+     * Playback command type: select the given track.
+     */
+    public static final String PLAYBACK_COMMAND_TYPE_SELECT_TRACK = "select_track";
+    /**
+     * Playback command parameter: channel URI.
+     * <p>Type: android.net.Uri
+     *
+     * @see #PLAYBACK_COMMAND_TYPE_TUNE
+     */
     public static final String COMMAND_PARAMETER_KEY_CHANNEL_URI = "command_channel_uri";
-    /** @hide */
+    /**
+     * Playback command parameter: TV input ID.
+     * <p>Type: String
+     *
+     * @see TvInputInfo#getId()
+     */
     public static final String COMMAND_PARAMETER_KEY_INPUT_ID = "command_input_id";
-    /** @hide */
+    /**
+     * Playback command parameter: stream volume.
+     * <p>Type: float
+     *
+     * @see #PLAYBACK_COMMAND_TYPE_SET_STREAM_VOLUME
+     */
     public static final String COMMAND_PARAMETER_KEY_VOLUME = "command_volume";
-    /** @hide */
+    /**
+     * Playback command parameter: track type.
+     * <p>Type: int
+     *
+     * @see #PLAYBACK_COMMAND_TYPE_SELECT_TRACK
+     * @see TvTrackInfo#getType()
+     */
     public static final String COMMAND_PARAMETER_KEY_TRACK_TYPE = "command_track_type";
-    /** @hide */
+    /**
+     * Playback command parameter: track ID.
+     * <p>Type: String
+     *
+     * @see #PLAYBACK_COMMAND_TYPE_SELECT_TRACK
+     * @see TvTrackInfo#getId()
+     */
     public static final String COMMAND_PARAMETER_KEY_TRACK_ID = "command_track_id";
-    /** @hide */
-    public static final String COMMAND_PARAMETER_KEY_TRACK_SELECT_MODE =
-            "command_track_select_mode";
     /**
      * Command to quiet channel change. No channel banner or channel info is shown.
      * <p>Refer to HbbTV Spec 2.0.4 chapter A.2.4.3.
-     * @hide
      */
     public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY =
             "command_change_channel_quietly";
@@ -145,9 +182,9 @@
     private final RemoteCallbackList<ITvInteractiveAppServiceCallback> mCallbacks =
             new RemoteCallbackList<>();
 
-    /** @hide */
     @Override
-    public final IBinder onBind(Intent intent) {
+    @Nullable
+    public final IBinder onBind(@NonNull Intent intent) {
         ITvInteractiveAppService.Stub tvIAppServiceBinder = new ITvInteractiveAppService.Stub() {
             @Override
             public void registerCallback(ITvInteractiveAppServiceCallback cb) {
@@ -210,24 +247,22 @@
      * Registers App link info.
      * @hide
      */
-    public void onRegisterAppLinkInfo(AppLinkInfo appLinkInfo) {
-        // TODO: make it abstract when unhide
+    public void onRegisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
     }
 
     /**
      * Unregisters App link info.
      * @hide
      */
-    public void onUnregisterAppLinkInfo(AppLinkInfo appLinkInfo) {
-        // TODO: make it abstract when unhide
+    public void onUnregisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
     }
 
     /**
-     * Sends App link info.
-     * @hide
+     * Called when app link command is received.
+     *
+     * @see android.media.tv.interactive.TvInteractiveAppManager#sendAppLinkCommand(String, Bundle)
      */
-    public void onAppLinkCommand(Bundle command) {
-        // TODO: make it abstract when unhide
+    public void onAppLinkCommand(@NonNull Bundle command) {
     }
 
 
@@ -317,7 +352,6 @@
          *
          * @param enable {@code true} if you want to enable the media view. {@code false}
          *            otherwise.
-         * @hide
          */
         public void setMediaViewEnabled(final boolean enable) {
             mHandler.post(new Runnable() {
@@ -352,7 +386,6 @@
 
         /**
          * Resets TvIAppService session.
-         * @hide
          */
         public void onResetInteractiveApp() {
         }
@@ -383,43 +416,37 @@
 
         /**
          * To toggle Digital Teletext Application if there is one in AIT app list.
-         * @param enable
-         * @hide
+         * @param enable {@code true} to enable teletext app; {@code false} otherwise.
          */
         public void onSetTeletextAppEnabled(boolean enable) {
         }
 
         /**
          * Receives current channel URI.
-         * @hide
          */
         public void onCurrentChannelUri(@Nullable Uri channelUri) {
         }
 
         /**
          * Receives logical channel number (LCN) of current channel.
-         * @hide
          */
         public void onCurrentChannelLcn(int lcn) {
         }
 
         /**
-         * Receives stream volume.
-         * @hide
+         * Receives current stream volume.
          */
         public void onStreamVolume(float volume) {
         }
 
         /**
          * Receives track list.
-         * @hide
          */
         public void onTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
         }
 
         /**
          * Receives current TV input ID.
-         * @hide
          */
         public void onCurrentTvInputId(@Nullable String inputId) {
         }
@@ -459,7 +486,6 @@
          *
          * @param width The width of the media view.
          * @param height The height of the media view.
-         * @hide
          */
         public void onMediaViewSizeChanged(int width, int height) {
         }
@@ -469,7 +495,6 @@
          * implementation can override this method and return its own view.
          *
          * @return a view attached to the media window
-         * @hide
          */
         @Nullable
         public View onCreateMediaView() {
@@ -478,10 +503,8 @@
 
         /**
          * Releases TvInteractiveAppService session.
-         * @hide
          */
-        public void onRelease() {
-        }
+        public abstract void onRelease();
 
         /**
          * Called when the corresponding TV input tuned to a channel.
@@ -493,49 +516,42 @@
 
         /**
          * Called when the corresponding TV input selected to a track.
-         * @hide
          */
-        public void onTrackSelected(int type, String trackId) {
+        public void onTrackSelected(@TvTrackInfo.Type int type, @NonNull String trackId) {
         }
 
         /**
          * Called when the tracks are changed.
-         * @hide
          */
-        public void onTracksChanged(List<TvTrackInfo> tracks) {
+        public void onTracksChanged(@NonNull List<TvTrackInfo> tracks) {
         }
 
         /**
          * Called when video is available.
-         * @hide
          */
         public void onVideoAvailable() {
         }
 
         /**
          * Called when video is unavailable.
-         * @hide
          */
-        public void onVideoUnavailable(int reason) {
+        public void onVideoUnavailable(@TvInputManager.VideoUnavailableReason int reason) {
         }
 
         /**
          * Called when content is allowed.
-         * @hide
          */
         public void onContentAllowed() {
         }
 
         /**
          * Called when content is blocked.
-         * @hide
          */
-        public void onContentBlocked(TvContentRating rating) {
+        public void onContentBlocked(@NonNull TvContentRating rating) {
         }
 
         /**
          * Called when signal strength is changed.
-         * @hide
          */
         public void onSignalStrength(@TvInputManager.SignalStrength int strength) {
         }
@@ -549,60 +565,61 @@
 
         /**
          * Called when an advertisement response is received.
-         * @hide
          */
-        public void onAdResponse(AdResponse response) {
+        public void onAdResponse(@NonNull AdResponse response) {
         }
 
-        /**
-         * TODO: JavaDoc of APIs related to input events.
-         * @hide
-         */
         @Override
         public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
             return false;
         }
 
-        /**
-         * @hide
-         */
         @Override
         public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
             return false;
         }
 
-        /**
-         * @hide
-         */
         @Override
         public boolean onKeyMultiple(int keyCode, int count, @NonNull KeyEvent event) {
             return false;
         }
 
-        /**
-         * @hide
-         */
         @Override
         public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
             return false;
         }
 
         /**
-         * @hide
+         * Implement this method to handle touch screen motion events on the current session.
+         *
+         * @param event The motion event being received.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         * @see View#onTouchEvent
          */
         public boolean onTouchEvent(@NonNull MotionEvent event) {
             return false;
         }
 
         /**
-         * @hide
+         * Implement this method to handle trackball events on the current session.
+         *
+         * @param event The motion event being received.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         * @see View#onTrackballEvent
          */
         public boolean onTrackballEvent(@NonNull MotionEvent event) {
             return false;
         }
 
         /**
-         * @hide
+         * Implement this method to handle generic motion events on the current session.
+         *
+         * @param event The motion event being received.
+         * @return If you handled the event, return {@code true}. If you want to allow the event to
+         *         be handled by the next receiver, return {@code false}.
+         * @see View#onGenericMotionEvent
          */
         public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
             return false;
@@ -692,13 +709,13 @@
         }
 
         /**
-         * requests a specific command to be processed by the related TV input.
+         * Sends a specific playback command to be processed by the related TV input.
+         *
          * @param cmdType type of the specific command
          * @param parameters parameters of the specific command
-         * @hide
          */
-        public void requestCommand(
-                @InteractiveAppServiceCommandType String cmdType, Bundle parameters) {
+        public void sendPlaybackCommandRequest(
+                @PlaybackCommandType @NonNull String cmdType, @Nullable Bundle parameters) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
                 @Override
@@ -720,9 +737,8 @@
 
         /**
          * Sets broadcast video bounds.
-         * @hide
          */
-        public void setVideoBounds(Rect rect) {
+        public void setVideoBounds(@NonNull Rect rect) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
                 @Override
@@ -743,7 +759,6 @@
 
         /**
          * Requests the URI of the current channel.
-         * @hide
          */
         public void requestCurrentChannelUri() {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -766,7 +781,6 @@
 
         /**
          * Requests the logic channel number (LCN) of the current channel.
-         * @hide
          */
         public void requestCurrentChannelLcn() {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -789,7 +803,6 @@
 
         /**
          * Requests stream volume.
-         * @hide
          */
         public void requestStreamVolume() {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -812,7 +825,6 @@
 
         /**
          * Requests the list of {@link TvTrackInfo}.
-         * @hide
          */
         public void requestTrackInfoList() {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -837,7 +849,6 @@
          * Requests current TV input ID.
          *
          * @see android.media.tv.TvInputInfo
-         * @hide
          */
         public void requestCurrentTvInputId() {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -859,9 +870,9 @@
         }
 
         /**
-         * requests an advertisement request to be processed by the related TV input.
-         * @param request advertisement request
-         * @hide
+         * Sends an advertisement request to be processed by the related TV input.
+         *
+         * @param request The advertisement request
          */
         public void requestAd(@NonNull final AdRequest request) {
             executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1080,7 +1091,6 @@
         /**
          * Notifies when the digital teletext app state is changed.
          * @param state the current state.
-         * @hide
          */
         public final void notifyTeletextAppStateChanged(
                 @TvInteractiveAppManager.TeletextAppState int state) {
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 2922bae..773e54f 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -170,23 +170,20 @@
         }
     }
 
-    /** @hide */
     @Override
-    protected void onAttachedToWindow() {
+    public void onAttachedToWindow() {
         super.onAttachedToWindow();
         createSessionMediaView();
     }
 
-    /** @hide */
     @Override
-    protected void onDetachedFromWindow() {
+    public void onDetachedFromWindow() {
         removeSessionMediaView();
         super.onDetachedFromWindow();
     }
 
-    /** @hide */
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
         if (DEBUG) {
             Log.d(TAG, "onLayout (left=" + left + ", top=" + top + ", right=" + right
                     + ", bottom=" + bottom + ",)");
@@ -199,9 +196,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         mSurfaceView.measure(widthMeasureSpec, heightMeasureSpec);
         int width = mSurfaceView.getMeasuredWidth();
         int height = mSurfaceView.getMeasuredHeight();
@@ -211,9 +207,8 @@
                         childState << MEASURED_HEIGHT_STATE_SHIFT));
     }
 
-    /** @hide */
     @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
+    public void onVisibilityChanged(@NonNull View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
         mSurfaceView.setVisibility(visibility);
         if (visibility == View.VISIBLE) {
@@ -244,7 +239,6 @@
 
     /**
      * Resets this TvInteractiveAppView.
-     * @hide
      */
     public void reset() {
         if (DEBUG) Log.d(TAG, "reset()");
@@ -330,7 +324,11 @@
 
     /**
      * Dispatches an unhandled input event to the next receiver.
-     * @hide
+     *
+     * It gives the host application a chance to dispatch the unhandled input events.
+     *
+     * @param event The input event.
+     * @return {@code true} if the event was handled by the view, {@code false} otherwise.
      */
     public boolean dispatchUnhandledInputEvent(@NonNull InputEvent event) {
         if (mOnUnhandledInputEventListener != null) {
@@ -349,21 +347,28 @@
      * @param event The input event.
      * @return If you handled the event, return {@code true}. If you want to allow the event to be
      *         handled by the next receiver, return {@code false}.
-     * @hide
      */
     public boolean onUnhandledInputEvent(@NonNull InputEvent event) {
         return false;
     }
 
     /**
-     * Registers a callback to be invoked when an input event is not handled
+     * Sets a listener to be invoked when an input event is not handled
      * by the TV Interactive App.
      *
      * @param listener The callback to be invoked when the unhandled input event is received.
-     * @hide
      */
-    public void setOnUnhandledInputEventListener(@NonNull OnUnhandledInputEventListener listener) {
+    public void setOnUnhandledInputEventListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnUnhandledInputEventListener listener) {
         mOnUnhandledInputEventListener = listener;
+        // TODO: handle CallbackExecutor
+    }
+    /**
+     * Clears the {@link OnUnhandledInputEventListener}.
+     */
+    public void clearOnUnhandledInputEventListener() {
+        mOnUnhandledInputEventListener = null;
     }
 
     @Override
@@ -427,7 +432,6 @@
 
     /**
      * Resets the interactive application.
-     * @hide
      */
     public void resetInteractiveApp() {
         if (DEBUG) {
@@ -440,9 +444,11 @@
 
     /**
      * Sends current channel URI to related TV interactive app.
-     * @hide
+     *
+     * @param channelUri The current channel URI; {@code null} if there is no currently tuned
+     *                   channel.
      */
-    public void sendCurrentChannelUri(Uri channelUri) {
+    public void sendCurrentChannelUri(@Nullable Uri channelUri) {
         if (DEBUG) {
             Log.d(TAG, "sendCurrentChannelUri");
         }
@@ -453,7 +459,6 @@
 
     /**
      * Sends current channel logical channel number (LCN) to related TV interactive app.
-     * @hide
      */
     public void sendCurrentChannelLcn(int lcn) {
         if (DEBUG) {
@@ -466,7 +471,6 @@
 
     /**
      * Sends stream volume to related TV interactive app.
-     * @hide
      */
     public void sendStreamVolume(float volume) {
         if (DEBUG) {
@@ -479,9 +483,8 @@
 
     /**
      * Sends track info list to related TV interactive app.
-     * @hide
      */
-    public void sendTrackInfoList(List<TvTrackInfo> tracks) {
+    public void sendTrackInfoList(@Nullable List<TvTrackInfo> tracks) {
         if (DEBUG) {
             Log.d(TAG, "sendTrackInfoList");
         }
@@ -496,7 +499,6 @@
      * @param inputId The current TV input ID whose channel is tuned. {@code null} if no channel is
      *                tuned.
      * @see android.media.tv.TvInputInfo
-     * @hide
      */
     public void sendCurrentTvInputId(@Nullable String inputId) {
         if (DEBUG) {
@@ -588,8 +590,11 @@
 
     /**
      * To toggle Digital Teletext Application if there is one in AIT app list.
-     * @param enable
-     * @hide
+     *
+     * <p>A Teletext Application is a broadcast-related application to display text and basic
+     * graphics.
+     *
+     * @param enable {@code true} to enable Teletext app; {@code false} to disable it.
      */
     public void setTeletextAppEnabled(boolean enable) {
         if (DEBUG) {
@@ -607,17 +612,17 @@
         // TODO: unhide the following public APIs
 
         /**
-         * This is called when a command is requested to be processed by the related TV input.
+         * This is called when a playback command is requested to be processed by the related TV
+         * input.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
          * @param cmdType type of the command
          * @param parameters parameters of the command
-         * @hide
          */
-        public void onCommandRequest(
+        public void onPlaybackCommandRequest(
                 @NonNull String iAppServiceId,
-                @NonNull @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
-                @Nullable Bundle parameters) {
+                @NonNull @TvInteractiveAppService.PlaybackCommandType String cmdType,
+                @NonNull Bundle parameters) {
         }
 
         /**
@@ -656,7 +661,6 @@
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
          * @param state digital teletext app current state.
-         * @hide
          */
         public void onTeletextAppStateChanged(
                 @NonNull String iAppServiceId,
@@ -664,59 +668,55 @@
         }
 
         /**
-         * This is called when {@link TvInteractiveAppService.Session#SetVideoBounds} is called.
+         * This is called when {@link TvInteractiveAppService.Session#setVideoBounds(Rect)} is
+         * called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
-         * @hide
          */
         public void onSetVideoBounds(@NonNull String iAppServiceId, @NonNull Rect rect) {
         }
 
         /**
-         * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelUri} is
+         * This is called when {@link TvInteractiveAppService.Session#requestCurrentChannelUri()} is
          * called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
-         * @hide
          */
         public void onRequestCurrentChannelUri(@NonNull String iAppServiceId) {
         }
 
         /**
-         * This is called when {@link TvInteractiveAppService.Session#RequestCurrentChannelLcn} is
+         * This is called when {@link TvInteractiveAppService.Session#requestCurrentChannelLcn()} is
          * called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
-         * @hide
          */
         public void onRequestCurrentChannelLcn(@NonNull String iAppServiceId) {
         }
 
         /**
-         * This is called when {@link TvInteractiveAppService.Session#RequestStreamVolume} is
+         * This is called when {@link TvInteractiveAppService.Session#requestStreamVolume()} is
          * called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
-         * @hide
          */
         public void onRequestStreamVolume(@NonNull String iAppServiceId) {
         }
 
         /**
-         * This is called when {@link TvInteractiveAppService.Session#RequestTrackInfoList} is
+         * This is called when {@link TvInteractiveAppService.Session#requestTrackInfoList()} is
          * called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
-         * @hide
          */
         public void onRequestTrackInfoList(@NonNull String iAppServiceId) {
         }
 
         /**
-         * This is called when {@link TvIAppService.Session#RequestCurrentTvInputId} is called.
+         * This is called when {@link TvInteractiveAppService.Session#requestCurrentTvInputId()} is
+         * called.
          *
          * @param iAppServiceId The ID of the TV interactive app service bound to this view.
-         * @hide
          */
         public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) {
         }
@@ -725,7 +725,6 @@
 
     /**
      * Interface definition for a callback to be invoked when the unhandled input event is received.
-     * @hide
      */
     public interface OnUnhandledInputEventListener {
         /**
@@ -818,7 +817,7 @@
         @Override
         public void onCommandRequest(
                 Session session,
-                @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
+                @TvInteractiveAppService.PlaybackCommandType String cmdType,
                 Bundle parameters) {
             if (DEBUG) {
                 Log.d(TAG, "onCommandRequest (cmdType=" + cmdType + ", parameters="
@@ -833,7 +832,8 @@
                     mCallbackExecutor.execute(() -> {
                         synchronized (mCallbackLock) {
                             if (mCallback != null) {
-                                mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
+                                mCallback.onPlaybackCommandRequest(
+                                        mIAppServiceId, cmdType, parameters);
                             }
                         }
                     });
diff --git a/media/java/android/media/tv/tuner/filter/SharedFilter.java b/media/java/android/media/tv/tuner/filter/SharedFilter.java
index 056c5d5..740ab9c 100644
--- a/media/java/android/media/tv/tuner/filter/SharedFilter.java
+++ b/media/java/android/media/tv/tuner/filter/SharedFilter.java
@@ -92,9 +92,21 @@
                     synchronized (mCallbackLock) {
                         if (mCallback != null) {
                             mCallback.onFilterEvent(this, events);
+                        } else {
+                            for (FilterEvent event : events) {
+                                if (event instanceof MediaEvent) {
+                                    ((MediaEvent)event).release();
+                                }
+                            }
                         }
                     }
                 });
+            } else {
+                for (FilterEvent event : events) {
+                    if (event instanceof MediaEvent) {
+                        ((MediaEvent)event).release();
+                    }
+                }
             }
         }
     }
@@ -187,6 +199,8 @@
             if (mIsClosed) {
                 return;
             }
+            mCallback = null;
+            mExecutor = null;
             nativeSharedClose();
             mIsClosed = true;
          }
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 2e419a6..eca26dc 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -460,8 +460,6 @@
     } else {
         // Set consumer buffer format to user specified format
         android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace);
-        int userFormat = static_cast<int>(mapHalFormatDataspaceToPublicFormat(
-            hardwareBufferFormat, nativeDataspace));
         res = native_window_set_buffers_format(anw.get(), hardwareBufferFormat);
         if (res != OK) {
             ALOGE("%s: Unable to configure consumer native buffer format to %#x",
@@ -478,20 +476,29 @@
             return 0;
         }
         ctx->setBufferDataSpace(nativeDataspace);
-        surfaceFormat = userFormat;
+        surfaceFormat = static_cast<int32_t>(mapHalFormatDataspaceToPublicFormat(
+            hardwareBufferFormat, nativeDataspace));
     }
 
     ctx->setBufferFormat(surfaceFormat);
     env->SetIntField(thiz,
             gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
 
-    res = native_window_set_usage(anw.get(), ndkUsage);
-    if (res != OK) {
-        ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
-              __FUNCTION__, static_cast<unsigned int>(ndkUsage),
-              surfaceFormat, strerror(-res), res);
-        jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
-        return 0;
+    // ndkUsage == -1 means setUsage in ImageWriter class is not called.
+    // skip usage setting if setUsage in ImageWriter is not called and imageformat is opaque.
+    if (!(ndkUsage == -1 && isFormatOpaque(surfaceFormat))) {
+        if (ndkUsage == -1) {
+            ndkUsage = GRALLOC_USAGE_SW_WRITE_OFTEN;
+        }
+        res = native_window_set_usage(anw.get(), ndkUsage);
+        if (res != OK) {
+            ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
+                  __FUNCTION__, static_cast<unsigned int>(ndkUsage),
+                  surfaceFormat, strerror(-res), res);
+            jniThrowRuntimeException(env,
+                                     "Failed to SW_WRITE_OFTEN configure usage");
+            return 0;
+        }
     }
 
     int minUndequeuedBufferCount = 0;
@@ -952,7 +959,7 @@
     return buffer->getHeight();
 }
 
-static jint Image_getFormat(JNIEnv* env, jobject thiz) {
+static jint Image_getFormat(JNIEnv* env, jobject thiz, jlong dataSpace) {
     ALOGV("%s", __FUNCTION__);
     GraphicBuffer* buffer;
     Image_getNativeContext(env, thiz, &buffer, NULL);
@@ -962,9 +969,9 @@
         return 0;
     }
 
-    // ImageWriter doesn't support data space yet, assuming it is unknown.
     PublicFormat publicFmt = mapHalFormatDataspaceToPublicFormat(buffer->getPixelFormat(),
-                                                                 HAL_DATASPACE_UNKNOWN);
+        static_cast<android_dataspace>(dataSpace));
+
     return static_cast<jint>(publicFmt);
 }
 
@@ -1031,14 +1038,14 @@
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
-        int numPlanes, int writerFormat) {
+        int numPlanes, int writerFormat, long dataSpace) {
     ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
     int rowStride, pixelStride;
     uint8_t *pData;
     uint32_t dataSize;
     jobject byteBuffer;
 
-    int format = Image_getFormat(env, thiz);
+    int format = Image_getFormat(env, thiz, dataSpace);
     if (isFormatOpaque(format) && numPlanes > 0) {
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
@@ -1108,11 +1115,11 @@
 };
 
 static JNINativeMethod gImageMethods[] = {
-    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
+    {"nativeCreatePlanes",      "(IIJ)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
                                                                (void*)Image_createSurfacePlanes },
     {"nativeGetWidth",          "()I",                         (void*)Image_getWidth },
     {"nativeGetHeight",         "()I",                         (void*)Image_getHeight },
-    {"nativeGetFormat",         "()I",                         (void*)Image_getFormat },
+    {"nativeGetFormat",         "(J)I",                        (void*)Image_getFormat },
     {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;",
                                                                (void*)Image_getHardwareBuffer },
 };
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 68dd8d0..9ed1ac0 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -4147,6 +4147,7 @@
 
     Result r = filterClient->close();
     filterClient->decStrong(filter);
+    filterClient = nullptr;
     if (shared) {
         env->SetLongField(filter, gFields.sharedFilterContext, 0);
     } else {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index d3d5a08..77fc171 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -434,7 +434,8 @@
         @NonNull
         public Builder setRatType(@Annotation.NetworkType int ratType) {
             if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType)
-                    && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+                    && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN
+                    && ratType != NetworkTemplate.NETWORK_TYPE_5G_NSA) {
                 throw new IllegalArgumentException("Invalid ratType " + ratType);
             }
             mRatType = ratType;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index cad8075..dba3991 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -652,7 +652,9 @@
      *
      * @hide
      */
-    public boolean matches(NetworkIdentity ident) {
+    @SystemApi(client = MODULE_LIBRARIES)
+    public boolean matches(@NonNull NetworkIdentity ident) {
+        Objects.requireNonNull(ident);
         if (!matchesMetered(ident)) return false;
         if (!matchesRoaming(ident)) return false;
         if (!matchesDefaultNetwork(ident)) return false;
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f9ac01d..e4eab4b 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1306,8 +1306,8 @@
 
     <!--  Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
     <string name="zen_mode_enable_dialog_turn_on">Turn on</string>
-    <!-- Do not disturb: Title for the Do not Disturb dialog to turn on Do not disturb. [CHAR LIMIT=50]-->
-    <string name="zen_mode_settings_turn_on_dialog_title">Turn on Do Not Disturb</string>
+    <!-- Priority mode: Title for the Priority mode dialog to turn on Priority mode. [CHAR LIMIT=50]-->
+    <string name="zen_mode_settings_turn_on_dialog_title" translatable="false">Turn on Priority mode</string>
     <!-- Sound: Summary for the Do not Disturb option when there is no automatic rules turned on. [CHAR LIMIT=NONE]-->
     <string name="zen_mode_settings_summary_off">Never</string>
     <!--[CHAR LIMIT=40] Zen Interruption level: Priority.  -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
index f5aa652..b4e84dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
+++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
@@ -27,9 +27,7 @@
 import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
-import android.net.wifi.WifiInfo;
 import android.os.AsyncTask;
-import android.text.TextUtils;
 import android.util.RecurrenceRule;
 
 import com.google.android.collect.Lists;
@@ -124,7 +122,7 @@
         if (policy != null) {
             return policy;
         } else {
-            return getPolicy(buildUnquotedNetworkTemplate(template));
+            return getPolicy(template);
         }
     }
 
@@ -207,21 +205,4 @@
         policy.clearSnooze();
         writeAsync();
     }
-
-    /**
-     * Build a revised {@link NetworkTemplate} that matches the same rule, but
-     * with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work
-     * around legacy bugs.
-     */
-    private static NetworkTemplate buildUnquotedNetworkTemplate(NetworkTemplate template) {
-        if (template == null) return null;
-        final String networkId = template.getNetworkId();
-        final String strippedNetworkId = WifiInfo.sanitizeSsid(networkId);
-        if (!TextUtils.equals(strippedNetworkId, networkId)) {
-            return new NetworkTemplate(
-                    template.getMatchRule(), template.getSubscriberId(), strippedNetworkId);
-        } else {
-            return null;
-        }
-    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index b56ae38..4939e04 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -88,14 +88,15 @@
     }
 
     /**
-     * Determine whether the device is plugged in (USB, power, or wireless).
+     * Determine whether the device is plugged in (USB, power, wireless or dock).
      *
      * @return true if the device is plugged in.
      */
     public boolean isPluggedIn() {
         return plugged == BatteryManager.BATTERY_PLUGGED_AC
                 || plugged == BatteryManager.BATTERY_PLUGGED_USB
-                || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
+                || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
+                || plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
     }
 
     /**
@@ -118,6 +119,15 @@
     }
 
     /**
+     * Determine whether the device is plugged in dock.
+     *
+     * @return true if the device is plugged in dock
+     */
+    public boolean isPluggedInDock() {
+        return plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
+    }
+
+    /**
      * Whether or not the device is charged. Note that some devices never return 100% for
      * battery level, so this allows either battery level or status to determine if the
      * battery is charged.
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS b/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS
new file mode 100644
index 0000000..ab9b5dc
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS
@@ -0,0 +1,4 @@
+# Default reviewers for this and subdirectories.
+bonianchen@google.com
+
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index cff45c6..30c6645 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.net;
 
-import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.telephony.TelephonyManager.SIM_STATE_READY;
 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
 import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
@@ -49,6 +48,7 @@
     private static final StringBuilder PERIOD_BUILDER = new StringBuilder(50);
     private static final java.util.Formatter PERIOD_FORMATTER = new java.util.Formatter(
             PERIOD_BUILDER, Locale.getDefault());
+    private static final long MB_IN_BYTES = 1024 * 1024;
 
     private final Context mContext;
     private final NetworkPolicyManager mPolicyManager;
@@ -237,10 +237,8 @@
         final int matchRule = networkTemplate.getMatchRule();
         switch (matchRule) {
             case NetworkTemplate.MATCH_MOBILE:
-            case NetworkTemplate.MATCH_MOBILE_WILDCARD:
                 return ConnectivityManager.TYPE_MOBILE;
             case NetworkTemplate.MATCH_WIFI:
-            case NetworkTemplate.MATCH_WIFI_WILDCARD:
                 return  ConnectivityManager.TYPE_WIFI;
             case NetworkTemplate.MATCH_ETHERNET:
                 return  ConnectivityManager.TYPE_ETHERNET;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
index afd44d5..386a47a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
@@ -63,14 +63,32 @@
     private static NetworkTemplate getNormalizedMobileTemplate(
             TelephonyManager telephonyManager, int subId) {
         final NetworkTemplate mobileTemplate = getMobileTemplateForSubId(telephonyManager, subId);
-        final String[] mergedSubscriberIds = telephonyManager
-                .createForSubscriptionId(subId).getMergedImsisFromGroup();
+        final Set<String> mergedSubscriberIds = Set.of(telephonyManager
+                .createForSubscriptionId(subId).getMergedImsisFromGroup());
         if (ArrayUtils.isEmpty(mergedSubscriberIds)) {
             Log.i(TAG, "mergedSubscriberIds is null.");
             return mobileTemplate;
         }
 
-        return NetworkTemplate.normalize(mobileTemplate, mergedSubscriberIds);
+        return normalizeMobileTemplate(mobileTemplate, mergedSubscriberIds);
+    }
+
+    private static NetworkTemplate normalizeMobileTemplate(
+            NetworkTemplate template, Set<String> mergedSet) {
+        if (template.getSubscriberIds().isEmpty()) return template;
+        // The input template should have at most 1 subscriberId.
+        final String subscriberId = template.getSubscriberIds().iterator().next();
+
+        if (mergedSet.contains(subscriberId)) {
+            // Requested template subscriber is part of the merge group; return
+            // a template that matches all merged subscribers.
+            return new NetworkTemplate.Builder(template.getMatchRule())
+                    .setSubscriberIds(mergedSet)
+                    .setWifiNetworkKeys(template.getWifiNetworkKeys())
+                    .setMeteredness(NetworkStats.METERED_YES).build();
+        }
+
+        return template;
     }
 
     private static NetworkTemplate getMobileTemplateForSubId(
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java
index 43c05b8..504390c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataForUidLoader.java
@@ -53,8 +53,9 @@
             long totalUsage = 0L;
             long totalForeground = 0L;
             for (int uid : mUids) {
-                final NetworkStats stats = mNetworkStatsManager.queryDetailsForUid(
-                        mNetworkTemplate, start, end, uid);
+                final NetworkStats stats = mNetworkStatsManager.queryDetailsForUidTagState(
+                        mNetworkTemplate, start, end, uid, NetworkStats.Bucket.TAG_NONE,
+                        NetworkStats.Bucket.STATE_ALL);
                 final long usage = getTotalUsage(stats);
                 if (usage > 0L) {
                     totalUsage += usage;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/OWNERS b/packages/SettingsLib/src/com/android/settingslib/net/OWNERS
new file mode 100644
index 0000000..ab9b5dc
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/OWNERS
@@ -0,0 +1,4 @@
+# Default reviewers for this and subdirectories.
+bonianchen@google.com
+
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
index 02326ea..623eb33 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -17,6 +17,7 @@
 package com.android.settingslib.net;
 
 import android.app.AppGlobals;
+import android.app.usage.NetworkStats;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
@@ -116,13 +117,13 @@
                 detail.label = res.getString(R.string.process_kernel_label);
                 detail.icon = pm.getDefaultActivityIcon();
                 return detail;
-            case TrafficStats.UID_REMOVED:
+            case NetworkStats.Bucket.UID_REMOVED:
                 detail.label = res.getString(UserManager.supportsMultipleUsers()
                         ? R.string.data_usage_uninstalled_apps_users
                         : R.string.data_usage_uninstalled_apps);
                 detail.icon = pm.getDefaultActivityIcon();
                 return detail;
-            case TrafficStats.UID_TETHERING:
+            case NetworkStats.Bucket.UID_TETHERING:
                 final TetheringManager tm = mContext.getSystemService(TetheringManager.class);
                 detail.label = res.getString(Utils.getTetheringLabel(tm));
                 detail.icon = pm.getDefaultActivityIcon();
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 1601043..8e9e02a 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -37,6 +37,9 @@
     <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50]  -->
     <string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging wirelessly</string>
 
+    <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's dock charging. [CHAR LIMIT=50]  -->
+    <string name="keyguard_plugged_in_dock"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging Dock</string>
+
     <!-- When the lock screen is showing and the phone plugged in, and the battery
          is not fully charged, say that it's charging.  -->
     <string name="keyguard_plugged_in"><xliff:g id="percentage">%s</xliff:g> • Charging</string>
diff --git a/packages/SystemUI/res/drawable/ic_list.xml b/packages/SystemUI/res/drawable/ic_list.xml
deleted file mode 100644
index 7ef5299..0000000
--- a/packages/SystemUI/res/drawable/ic_list.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2021 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-
-<!-- Remove when Fgs manager tile is removed -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path
-        android:pathData="M2,4h4v4h-4z"
-        android:fillColor="#000000"/>
-    <path
-        android:pathData="M8,4h14v4h-14z"
-        android:fillColor="#000000"/>
-    <path
-        android:pathData="M2,10h4v4h-4z"
-        android:fillColor="#000000"/>
-    <path
-        android:pathData="M8,10h14v4h-14z"
-        android:fillColor="#000000"/>
-    <path
-        android:pathData="M2,16h4v4h-4z"
-        android:fillColor="#000000"/>
-    <path
-        android:pathData="M8,16h14v4h-14z"
-        android:fillColor="#000000"/>
-</vector>
diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml
index 28fc863..4d2317c 100644
--- a/packages/SystemUI/res/layout/controls_detail_dialog.xml
+++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml
@@ -15,47 +15,52 @@
      limitations under the License.
 -->
 
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/control_detail_root"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:background="@android:color/black">
+    android:layout_height="match_parent">
   <LinearLayout
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:layout_marginBottom="4dp">
-    <ImageView
-        android:id="@+id/control_detail_close"
-        android:contentDescription="@string/accessibility_desc_close"
-        android:src="@drawable/ic_arrow_back"
-        android:background="?android:attr/selectableItemBackgroundBorderless"
-        android:tint="@color/control_primary_text"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:padding="12dp" />
-    <Space
-        android:layout_width="0dp"
-        android:layout_weight="1"
-        android:layout_height="1dp" />
-    <ImageView
-        android:id="@+id/control_detail_open_in_app"
-        android:contentDescription="@string/controls_open_app"
-        android:src="@drawable/ic_open_in_new"
-        android:background="?android:attr/selectableItemBackgroundBorderless"
-        android:tint="@color/control_primary_text"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:padding="12dp" />
-  </LinearLayout>
-
-  <FrameLayout
-      android:id="@+id/controls_activity_view"
+      android:id="@+id/control_task_view_container"
       android:layout_width="match_parent"
-      android:layout_height="0dp"
-      android:layout_weight="1"
-      android:orientation="vertical" />
-</LinearLayout>
+      android:layout_height="match_parent"
+      android:layout_gravity="right|top"
+      android:layout_marginRight="@dimen/controls_task_view_right_margin"
+      android:orientation="vertical">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_marginBottom="4dp">
+      <ImageView
+          android:id="@+id/control_detail_close"
+          android:contentDescription="@string/accessibility_desc_close"
+          android:src="@drawable/ic_close"
+          android:background="?android:attr/selectableItemBackgroundBorderless"
+          android:tint="@color/control_primary_text"
+          android:layout_width="48dp"
+          android:layout_height="48dp"
+          android:padding="12dp" />
+      <Space
+          android:layout_width="0dp"
+          android:layout_weight="1"
+          android:layout_height="1dp" />
+      <ImageView
+          android:id="@+id/control_detail_open_in_app"
+          android:contentDescription="@string/controls_open_app"
+          android:src="@drawable/ic_open_in_new"
+          android:background="?android:attr/selectableItemBackgroundBorderless"
+          android:tint="@color/control_primary_text"
+          android:layout_width="48dp"
+          android:layout_height="48dp"
+          android:padding="12dp" />
+    </LinearLayout>
+
+    <FrameLayout
+        android:id="@+id/controls_activity_view"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+  </LinearLayout>
+</FrameLayout>
 
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 3cfe056..89d046b 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -25,4 +25,8 @@
     <!-- margin from keyguard status bar to clock. For split shade it should be
          keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
     <dimen name="keyguard_clock_top_margin">8dp</dimen>
+
+    <!-- Limit the TaskView to this percentage of the overall screen width (0.0 - 1.0) -->
+    <item name="controls_task_view_width_percentage" translatable="false" format="float" type="dimen">0.45</item>
+    <dimen name="controls_task_view_right_margin">8dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 461a598..81e3e04 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -194,6 +194,7 @@
     <color name="control_enabled_cool_foreground">@color/GM2_blue_300</color>
     <color name="control_thumbnail_tint">#33000000</color>
     <color name="control_thumbnail_shadow_color">@*android:color/black</color>
+    <color name="controls_task_view_bg">#CC191C1D</color>
 
     <!-- Docked misalignment message -->
     <color name="misalignment_text_color">#F28B82</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index fc2756e..9d7cf1a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -82,7 +82,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,fgsmanager,color_correction
+        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction
     </string>
 
     <!-- The tiles to display in QuickSettings -->
@@ -581,6 +581,9 @@
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">false</bool>
 
+    <!-- Whether notification header should never show section headers. -->
+    <bool name="config_notification_never_show_section_headers">false</bool>
+
     <!-- Default udfps icon. Same path as ic_fingerprint.xml -->
     <string name="config_udfpsIcon" translatable="false">
         M25.5,16.3283C28.47,14.8433 31.9167,14 35.5834,14C39.2501,14 42.6968,14.8433 45.6668,16.3283
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 67d5b2f..af7ef53 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1052,6 +1052,9 @@
     <dimen name="controls_setup_subtitle">14sp</dimen>
     <dimen name="controls_setup_vertical_padding">52dp</dimen>
     <dimen name="controls_detail_dialog_header_height">52dp</dimen>
+    <!-- Limit the TaskView to this percentage of the overall screen width (0.0 - 1.0) -->
+    <item name="controls_task_view_width_percentage" translatable="false" format="float" type="dimen">1.0</item>
+    <dimen name="controls_task_view_right_margin">0dp</dimen>
 
     <!-- Home Controls activity view detail panel-->
     <dimen name="controls_activity_view_corner_radius">@*android:dimen/config_bottomDialogCornerRadius</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1835d2b..6eab2b2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -429,8 +429,8 @@
     <string name="accessibility_quick_settings_dnd_none_on">total silence</string>
     <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_alarms_on">alarms only</string>
-     <!-- Content description of the do not disturb tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_dnd">Do Not Disturb.</string>
+     <!-- Content description of the priority mode tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd" translatable="false">Priority mode.</string>
     <!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth">Bluetooth.</string>
     <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -508,8 +508,8 @@
     <string name="ethernet_label">Ethernet</string>
 
     <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
-    <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_dnd_label">Do Not Disturb</string>
+    <!-- QuickSettings: Priority mode [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_label" translatable="false">Priority mode</string>
     <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
     <!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] -->
     <!-- QuickSettings: Do not disturb - Total silence [CHAR LIMIT=NONE] -->
@@ -796,6 +796,9 @@
     <!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=50]-->
     <string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
 
+    <!-- Indication on the keyguard that is shown when the device is dock charging. [CHAR LIMIT=80]-->
+    <string name="keyguard_indication_charging_time_dock"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Charging Dock • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
+
     <!-- Related to user switcher --><skip/>
 
     <!-- Accessibility label for the button that opens the user switcher. -->
@@ -896,8 +899,8 @@
     <!-- Content description for accessibility: Tapping this button will dismiss all gentle notifications [CHAR LIMIT=NONE] -->
     <string name="accessibility_notification_section_header_gentle_clear_all">Clear all silent notifications</string>
 
-    <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
-    <string name="dnd_suppressing_shade_text">Notifications paused by Do Not Disturb</string>
+    <!-- The text to show in the notifications shade when Priority mode is suppressing notifications. [CHAR LIMIT=100] -->
+    <string name="dnd_suppressing_shade_text" translatable="false">Notifications paused by Priority mode</string>
 
     <!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
     <string name="media_projection_action_text">Start now</string>
@@ -1319,8 +1322,8 @@
     <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level summary -->
     <string name="notification_channel_summary_priority_baseline">Shows at the top of conversation notifications and as a profile picture on lock screen</string>
     <string name="notification_channel_summary_priority_bubble">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble</string>
-    <string name="notification_channel_summary_priority_dnd">Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb</string>
-    <string name="notification_channel_summary_priority_all">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb</string>
+    <string name="notification_channel_summary_priority_dnd" translatable="false">Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Priority mode</string>
+    <string name="notification_channel_summary_priority_all" translatable="false">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Priority mode</string>
 
     <!-- [CHAR LIMIT=150] Notification Importance title: important conversation level -->
     <string name="notification_priority_title">Priority</string>
@@ -1511,8 +1514,8 @@
     <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
     <string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
 
-    <!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
-    <string name="volume_and_do_not_disturb">Do Not Disturb</string>
+    <!-- SysUI Tuner: Label for screen about priority mode settings [CHAR LIMIT=60] -->
+    <string name="volume_and_do_not_disturb" translatable="false">Priority mode</string>
 
     <!-- SysUI Tuner: Switch to control whether volume buttons enter/exit do
          not disturb [CHAR LIMIT=60] -->
@@ -1873,17 +1876,17 @@
     <!-- Label for when bluetooth is off in QS detail panel [CHAR LIMIT=NONE] -->
     <string name="bt_is_off">Bluetooth is off</string>
 
-    <!-- Label for when Do not disturb is off in QS detail panel [CHAR LIMIT=NONE] -->
-    <string name="dnd_is_off">Do Not Disturb is off</string>
+    <!-- Label for when Priority mode is off in QS detail panel [CHAR LIMIT=NONE] -->
+    <string name="dnd_is_off" translatable="false">Priority mode is off</string>
 
-    <!-- Prompt for when Do not disturb is on from automatic rule in QS [CHAR LIMIT=NONE] -->
-    <string name="qs_dnd_prompt_auto_rule">Do Not Disturb was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>).</string>
+    <!-- Prompt for when Priority mode is on from automatic rule in QS [CHAR LIMIT=NONE] -->
+    <string name="qs_dnd_prompt_auto_rule" translatable="false">Priority mode was turned on by an automatic rule (<xliff:g name="rule">%s</xliff:g>).</string>
 
-    <!-- Prompt for when Do not disturb is on from app in QS [CHAR LIMIT=NONE] -->
-    <string name="qs_dnd_prompt_app">Do Not Disturb was turned on by an app (<xliff:g name="app">%s</xliff:g>).</string>
+    <!-- Prompt for when Priority mode is on from app in QS [CHAR LIMIT=NONE] -->
+    <string name="qs_dnd_prompt_app" translatable="false">Priority mode was turned on by an app (<xliff:g name="app">%s</xliff:g>).</string>
 
-    <!-- Prompt for when Do not disturb is on from automatic rule or app in QS [CHAR LIMIT=NONE] -->
-    <string name="qs_dnd_prompt_auto_rule_app">Do Not Disturb was turned on by an automatic rule or app.</string>
+    <!-- Prompt for when Priority mode is on from automatic rule or app in QS [CHAR LIMIT=NONE] -->
+    <string name="qs_dnd_prompt_auto_rule_app" translatable="false">Priority mode was turned on by an automatic rule or app.</string>
 
     <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
     <string name="running_foreground_services_title">Apps running in background</string>
@@ -2268,8 +2271,8 @@
     <string name="people_tile_description">See recent messages, missed calls, and status updates</string>
     <!-- Title text displayed for the Conversation widget [CHAR LIMIT=50] -->
     <string name="people_tile_title">Conversation</string>
-    <!-- Text when the Conversation widget when Do Not Disturb is suppressing the notification. [CHAR LIMIT=50] -->
-    <string name="paused_by_dnd">Paused by Do Not Disturb</string>
+    <!-- Text when the Conversation widget when Priority mode is suppressing the notification. [CHAR LIMIT=50] -->
+    <string name="paused_by_dnd" translatable="false">Paused by Priority mode</string>
     <!-- Content description text on the Conversation widget when a person has sent a new text message [CHAR LIMIT=150] -->
     <string name="new_notification_text_content_description"><xliff:g id="name" example="Anna">%1$s</xliff:g> sent a message: <xliff:g id="notification" example="Hey! How is your day going">%2$s</xliff:g></string>
     <!-- Content description text on the Conversation widget when a person has sent a new image message [CHAR LIMIT=150] -->
@@ -2355,6 +2358,11 @@
     <!-- Title for User Switch dialog. [CHAR LIMIT=20] -->
     <string name="qs_user_switch_dialog_title">Select user</string>
 
+    <!-- Label for the entry point to open the dialog which shows currently running applications [CHAR LIMIT=NONE]-->
+    <plurals name="fgs_manager_footer_label">
+        <item quantity="one"><xliff:g id="count" example="1">%s</xliff:g> app running in the background</item>
+        <item quantity="other"><xliff:g id="count" example="2">%s</xliff:g> apps running in the background</item>
+    </plurals>
     <!-- Title for dialog listing applications currently running in the backing [CHAR LIMIT=NONE]-->
     <string name="fgs_manager_dialog_title">Apps running in the background</string>
     <!-- Label of the button to stop the app from running in the background [CHAR LIMIT=12]-->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ff5699b..ac98739 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -746,7 +746,7 @@
      <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
       <item name="android:windowFullscreen">false</item>
       <item name="android:windowIsFloating">false</item>
-      <item name="android:windowBackground">@android:color/black</item>
+      <item name="android:windowBackground">@color/controls_task_view_bg</item>
       <item name="android:backgroundDimEnabled">false</item>
       <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
     </style>
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index a610caa..e273416 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -308,14 +308,4 @@
         <item>Off</item>
         <item>On</item>
     </string-array>
-
-    <!-- State names for fgsmanager tile: unavailable, off, on.
-         This subtitle is shown when the tile is in that particular state but does not set its own
-         subtitle, so some of these may never appear on screen. They should still be translated as
-         if they could appear.[CHAR LIMIT=32] -->
-    <string-array name="tile_states_fgsmanager">
-        <item>Unavailable</item>
-        <item>Off</item>
-        <item>On</item>
-    </string-array>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
index 710980a..e6d5719 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
@@ -58,7 +58,7 @@
 
     LayoutInflater mInflater;
 
-    private MetricsLogger mMetricsLogger;
+    private final MetricsLogger mMetricsLogger;
 
     private String[] mPackages;
     private PackageItemAdapter mAdapter;
@@ -75,16 +75,15 @@
             };
 
     @Inject
-    ForegroundServicesDialog() {
+    ForegroundServicesDialog(MetricsLogger metricsLogger) {
         super();
+        mMetricsLogger = metricsLogger;
     }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mMetricsLogger = Dependency.get(MetricsLogger.class);
-
         mInflater = LayoutInflater.from(this);
 
         mAdapter = new PackageItemAdapter(this);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 3f5c2c8..aedaf96 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -28,7 +28,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.systemui.BootCompleteCache;
-import com.android.systemui.Dependency;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -78,10 +77,11 @@
 
     @Inject
     PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher,
-            Lazy<Optional<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache) {
+            Lazy<Optional<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache,
+            StatusBarStateController statusBarStateController) {
         mContext = context;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
-        mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+        mStatusBarStateController = statusBarStateController;
 
         mDefaultHome = getCurrentDefaultHome();
         bootCompleteCache.addListener(() -> mDefaultHome = getCurrentDefaultHome());
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index 5732145..1c98099 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -35,7 +35,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistLogger;
 import com.android.systemui.assist.AssistManager;
@@ -46,6 +45,8 @@
 
 import javax.inject.Inject;
 
+import dagger.Lazy;
+
 /**
  * Default UiController implementation. Shows white edge lights along the bottom of the phone,
  * expanding from the corners to meet in the center.
@@ -65,6 +66,8 @@
     protected final AssistLogger mAssistLogger;
 
     private final WindowManager mWindowManager;
+    private final MetricsLogger mMetricsLogger;
+    private final Lazy<AssistManager> mAssistManagerLazy;
     private final WindowManager.LayoutParams mLayoutParams;
     private final PathInterpolator mProgressInterpolator = new PathInterpolator(.83f, 0, .84f, 1);
 
@@ -75,10 +78,14 @@
     private ValueAnimator mInvocationAnimator = new ValueAnimator();
 
     @Inject
-    public DefaultUiController(Context context, AssistLogger assistLogger) {
+    public DefaultUiController(Context context, AssistLogger assistLogger,
+            WindowManager windowManager, MetricsLogger metricsLogger,
+            Lazy<AssistManager> assistManagerLazy) {
         mAssistLogger = assistLogger;
         mRoot = new FrameLayout(context);
-        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        mWindowManager = windowManager;
+        mMetricsLogger = metricsLogger;
+        mAssistManagerLazy = assistManagerLazy;
 
         mLayoutParams = new WindowManager.LayoutParams(
                 WindowManager.LayoutParams.MATCH_PARENT,
@@ -152,9 +159,9 @@
                     /* isInvocationComplete = */ false,
                     /* assistantComponent = */ null,
                     /* legacyDeviceState = */ null);
-            MetricsLogger.action(new LogMaker(MetricsEvent.ASSISTANT)
+            mMetricsLogger.write(new LogMaker(MetricsEvent.ASSISTANT)
                     .setType(MetricsEvent.TYPE_ACTION)
-                    .setSubtype(Dependency.get(AssistManager.class).toLoggingSubType(type)));
+                    .setSubtype(mAssistManagerLazy.get().toLoggingSubType(type)));
         }
         // Logs assistant invocation cancelled.
         if ((mInvocationAnimator == null || !mInvocationAnimator.isRunning())
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index fd37b35..21edb24 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -52,7 +52,6 @@
 import android.widget.ScrollView;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -106,7 +105,7 @@
 
     private final float mTranslationY;
 
-    @VisibleForTesting final WakefulnessLifecycle mWakefulnessLifecycle;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
 
     @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
 
@@ -187,10 +186,12 @@
 
         public AuthContainerView build(int[] sensorIds, boolean credentialAllowed,
                 @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
-                @Nullable List<FaceSensorPropertiesInternal> faceProps) {
+                @Nullable List<FaceSensorPropertiesInternal> faceProps,
+                WakefulnessLifecycle wakefulnessLifecycle) {
             mConfig.mSensorIds = sensorIds;
             mConfig.mCredentialAllowed = credentialAllowed;
-            return new AuthContainerView(mConfig, new Injector(), fpProps, faceProps);
+            return new AuthContainerView(
+                    mConfig, new Injector(), fpProps, faceProps, wakefulnessLifecycle);
         }
     }
 
@@ -276,7 +277,8 @@
     @VisibleForTesting
     AuthContainerView(Config config, Injector injector,
             @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
-            @Nullable List<FaceSensorPropertiesInternal> faceProps) {
+            @Nullable List<FaceSensorPropertiesInternal> faceProps,
+            WakefulnessLifecycle wakefulnessLifecycle) {
         super(config.mContext);
 
         mConfig = config;
@@ -289,7 +291,7 @@
 
         mHandler = new Handler(Looper.getMainLooper());
         mWindowManager = mContext.getSystemService(WindowManager.class);
-        mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
+        mWakefulnessLifecycle = wakefulnessLifecycle;
 
         mTranslationY = getResources()
                 .getDimension(R.dimen.biometric_dialog_animation_translation_offset);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 2b12f67..f833c2a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -63,6 +63,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.util.concurrency.Execution;
 
@@ -130,6 +131,7 @@
 
     @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
     private SensorPrivacyManager mSensorPrivacyManager;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
 
     private class BiometricTaskStackListener extends TaskStackListener {
         @Override
@@ -479,9 +481,11 @@
             Provider<UdfpsController> udfpsControllerFactory,
             Provider<SidefpsController> sidefpsControllerFactory,
             @NonNull DisplayManager displayManager,
+            WakefulnessLifecycle wakefulnessLifecycle,
             @Main Handler handler) {
         super(context);
         mExecution = execution;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
         mHandler = handler;
         mCommandQueue = commandQueue;
         mActivityTaskManager = activityTaskManager;
@@ -788,7 +792,8 @@
                 skipAnimation,
                 operationId,
                 requestId,
-                multiSensorConfig);
+                multiSensorConfig,
+                mWakefulnessLifecycle);
 
         if (newDialog == null) {
             Log.e(TAG, "Unsupported type configuration");
@@ -868,7 +873,8 @@
     protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
             int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
             boolean skipIntro, long operationId, long requestId,
-            @BiometricMultiSensorMode int multiSensorConfig) {
+            @BiometricMultiSensorMode int multiSensorConfig,
+            WakefulnessLifecycle wakefulnessLifecycle) {
         return new AuthContainerView.Builder(mContext)
                 .setCallback(this)
                 .setPromptInfo(promptInfo)
@@ -879,7 +885,7 @@
                 .setOperationId(operationId)
                 .setRequestId(requestId)
                 .setMultiSensorConfig(multiSensorConfig)
-                .build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
+                .build(sensorIds, credentialAllowed, mFpProps, mFaceProps, wakefulnessLifecycle);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 6581490..5ddfd75 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Point;
 import android.graphics.RectF;
 import android.hardware.biometrics.SensorLocationInternal;
 import android.hardware.display.DisplayManager;
@@ -45,6 +46,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.WindowManager;
@@ -414,8 +416,33 @@
                         final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
                         if (!isIlluminationRequested && !mGoodCaptureReceived &&
                                 !exceedsVelocityThreshold) {
-                            onFingerDown((int) event.getRawX(), (int) event.getRawY(), minor,
-                                    major);
+                            final int rawX = (int) event.getRawX();
+                            final int rawY = (int) event.getRawY();
+                            // Default coordinates assume portrait mode.
+                            int x = rawX;
+                            int y = rawY;
+
+                            // Gets the size based on the current rotation of the display.
+                            Point p = new Point();
+                            mContext.getDisplay().getRealSize(p);
+
+                            // Transform x, y to portrait mode if the device is in landscape mode.
+                            switch (mContext.getDisplay().getRotation()) {
+                                case Surface.ROTATION_90:
+                                    x = p.y - rawY;
+                                    y = rawX;
+                                    break;
+
+                                case Surface.ROTATION_270:
+                                    x = rawY;
+                                    y = p.x - rawX;
+                                    break;
+
+                                default:
+                                    // Do nothing to stay in portrait mode.
+                            }
+
+                            onFingerDown(x, y, minor, major);
                             Log.v(TAG, "onTouch | finger down: " + touchInfo);
                             mTouchLogTime = mSystemClock.elapsedRealtime();
                             mPowerManager.userActivity(mSystemClock.uptimeMillis(),
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 4758ab0..dc3d1b5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -41,12 +41,12 @@
  * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}.
  */
 class DetailDialog(
-    val activityContext: Context?,
+    val activityContext: Context,
     val taskView: TaskView,
     val pendingIntent: PendingIntent,
     val cvh: ControlViewHolder
 ) : Dialog(
-    activityContext ?: cvh.context,
+    activityContext,
     R.style.Theme_SystemUI_Dialog_Control_DetailPanel
 ) {
     companion object {
@@ -58,6 +58,10 @@
     }
 
     var detailTaskId = INVALID_TASK_ID
+    private lateinit var taskViewContainer: View
+    private val taskWidthPercentWidth = activityContext.resources.getFloat(
+        R.dimen.controls_task_view_width_percentage
+    )
 
     private val fillInIntent = Intent().apply {
         putExtra(EXTRA_USE_PANEL, true)
@@ -75,13 +79,18 @@
 
     val stateCallback = object : TaskView.Listener {
         override fun onInitialized() {
-            val options = activityContext?.let {
-                ActivityOptions.makeCustomAnimation(
-                    it,
-                    0 /* enterResId */,
-                    0 /* exitResId */
-                )
-            } ?: ActivityOptions.makeBasic()
+            taskViewContainer.apply {
+                // For some devices, limit the overall width of the taskView
+                val lp = getLayoutParams()
+                lp.width = (getWidth() * taskWidthPercentWidth).toInt()
+                setLayoutParams(lp)
+            }
+
+            val options = ActivityOptions.makeCustomAnimation(
+                activityContext,
+                0 /* enterResId */,
+                0 /* exitResId */
+            )
             taskView.startActivity(
                 pendingIntent,
                 fillInIntent,
@@ -112,16 +121,14 @@
     }
 
     init {
-        if (activityContext == null) {
-            window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
-        }
-
         // To pass touches to the task inside TaskView.
         window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
         window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
 
         setContentView(R.layout.controls_detail_dialog)
 
+        taskViewContainer = requireViewById<ViewGroup>(R.id.control_task_view_container)
+
         requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
             addView(taskView)
             setAlpha(0f)
@@ -130,6 +137,9 @@
         requireViewById<ImageView>(R.id.control_detail_close).apply {
             setOnClickListener { _: View -> dismiss() }
         }
+        requireViewById<View>(R.id.control_detail_root).apply {
+            setOnClickListener { _: View -> dismiss() }
+        }
 
         requireViewById<ImageView>(R.id.control_detail_open_in_app).apply {
             setOnClickListener { v: View ->
@@ -145,17 +155,10 @@
         // consume all insets to achieve slide under effect
         window.getDecorView().setOnApplyWindowInsetsListener {
             v: View, insets: WindowInsets ->
-                taskView.apply {
-                    val l = getPaddingLeft()
-                    val t = getPaddingTop()
-                    val r = getPaddingRight()
-                    setPadding(l, t, r, insets.getInsets(Type.systemBars()).bottom)
-                }
-
                 val l = v.getPaddingLeft()
-                val b = v.getPaddingBottom()
                 val r = v.getPaddingRight()
-                v.setPadding(l, insets.getInsets(Type.systemBars()).top, r, b)
+                val insets = insets.getInsets(Type.systemBars())
+                v.setPadding(l, insets.top, r, insets.bottom)
 
                 WindowInsets.CONSUMED
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index e465ae4..85c9644 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -77,6 +77,10 @@
 
     @Override
     public int getItemCount() {
+        if (mController.isZeroMode()) {
+            // Add extra one for "pair new" or dynamic group
+            return mController.getMediaDevices().size() + 1;
+        }
         return mController.getMediaDevices().size();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt
new file mode 100644
index 0000000..0453fdb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media.nearby
+
+import com.android.systemui.dagger.SysUISingleton
+
+/**
+ * A manager that returns information about devices that are nearby and can receive media transfers.
+ */
+@SysUISingleton
+class MediaNearbyDevicesManager {
+
+    /** Returns a list containing the current nearby devices. */
+    fun getCurrentNearbyDevices(): List<NearbyDevice> {
+        // TODO(b/216313420): Implement this function.
+        return emptyList()
+    }
+
+    /**
+     * Registers [callback] to be notified each time a device's range changes or when a new device
+     * comes within range.
+     */
+    fun registerNearbyDevicesCallback(
+        callback: (device: NearbyDevice) -> Unit
+    ) {
+        // TODO(b/216313420): Implement this function.
+    }
+
+    /**
+     * Un-registers [callback]. See [registerNearbyDevicesCallback].
+     */
+    fun unregisterNearbyDevicesCallback(
+        callback: (device: NearbyDevice) -> Unit
+    ) {
+        // TODO(b/216313420): Implement this function.
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt
new file mode 100644
index 0000000..96b853f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media.nearby
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * A parcelable representing a nearby device that can be used for media transfer.
+ *
+ * This class includes:
+ *   - [routeId] identifying the media route
+ *   - [rangeZone] specifying how far away the device with the media route is from this device.
+ */
+class NearbyDevice(parcel: Parcel) : Parcelable {
+    var routeId: String? = null
+    @RangeZone val rangeZone: Int
+
+    init {
+        routeId = parcel.readString() ?: "unknown"
+        rangeZone = parcel.readInt()
+    }
+
+    override fun describeContents() = 0
+
+    override fun writeToParcel(out: Parcel, flags: Int) {
+        out.writeString(routeId)
+        out.writeInt(rangeZone)
+    }
+
+    companion object CREATOR : Parcelable.Creator<NearbyDevice?> {
+        override fun createFromParcel(parcel: Parcel) = NearbyDevice(parcel)
+        override fun newArray(size: Int) = arrayOfNulls<NearbyDevice?>(size)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt
new file mode 100644
index 0000000..3c890bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.media.nearby
+
+import androidx.annotation.IntDef
+import kotlin.annotation.AnnotationRetention
+
+@IntDef(
+        RangeZone.RANGE_UNKNOWN,
+        RangeZone.RANGE_FAR,
+        RangeZone.RANGE_LONG,
+        RangeZone.RANGE_CLOSE,
+        RangeZone.RANGE_WITHIN_REACH
+)
+@Retention(AnnotationRetention.SOURCE)
+/** The various range zones a device can be in, in relation to the current device. */
+annotation class RangeZone {
+    companion object {
+        /** Unknown distance range. */
+        const val RANGE_UNKNOWN = 0
+        /** Distance is very far away from the peer device. */
+        const val RANGE_FAR = 1
+        /** Distance is relatively long from the peer device, typically a few meters. */
+        const val RANGE_LONG = 2
+        /** Distance is close to the peer device, typically with one or two meter. */
+        const val RANGE_CLOSE = 3
+        /** Distance is very close to the peer device, typically within one meter or less. */
+        const val RANGE_WITHIN_REACH = 4
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index ad4a2f4..dbd641b 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -58,7 +58,6 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 import com.android.settingslib.utils.PowerUtil;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.dagger.SysUISingleton;
@@ -421,7 +420,7 @@
                                     new Intent(Intent.ACTION_VIEW)
                                             .setData(Uri.parse(url))
                                             .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                            Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+                            mActivityStarter.startActivity(helpIntent,
                                     true /* dismissShade */, resultCode -> {
                                         mHighTempDialog = null;
                                     });
@@ -456,7 +455,7 @@
                                     new Intent(Intent.ACTION_VIEW)
                                             .setData(Uri.parse(url))
                                             .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                            Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+                            mActivityStarter.startActivity(helpIntent,
                                     true /* dismissShade */, resultCode -> {
                                         mThermalShutdownDialog = null;
                                     });
@@ -516,7 +515,7 @@
                     helpIntent.setClassName("com.android.settings",
                             "com.android.settings.HelpTrampoline");
                     helpIntent.putExtra(Intent.EXTRA_TEXT, contextString);
-                    Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+                    mActivityStarter.startActivity(helpIntent,
                             true /* dismissShade */, resultCode -> {
                                 mUsbHighTempDialog = null;
                             });
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 37a0f59..642af59 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -43,7 +43,6 @@
 import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
@@ -80,13 +79,13 @@
     @VisibleForTesting
     final Receiver mReceiver = new Receiver();
 
-    private PowerManager mPowerManager;
-    private WarningsUI mWarnings;
+    private final PowerManager mPowerManager;
+    private final WarningsUI mWarnings;
     private InattentiveSleepWarningView mOverlayView;
     private final Configuration mLastConfiguration = new Configuration();
     private int mPlugType = 0;
     private int mInvalidCharger = 0;
-    private EnhancedEstimates mEnhancedEstimates;
+    private final EnhancedEstimates mEnhancedEstimates;
     private Future mLastShowWarningTask;
     private boolean mEnableSkinTemperatureWarning;
     private boolean mEnableUsbTemperatureAlarm;
@@ -113,18 +112,20 @@
 
     @Inject
     public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
-            CommandQueue commandQueue, Lazy<Optional<StatusBar>> statusBarOptionalLazy) {
+            CommandQueue commandQueue, Lazy<Optional<StatusBar>> statusBarOptionalLazy,
+            WarningsUI warningsUI, EnhancedEstimates enhancedEstimates,
+            PowerManager powerManager) {
         super(context);
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
+        mWarnings = warningsUI;
+        mEnhancedEstimates = enhancedEstimates;
+        mPowerManager = powerManager;
     }
 
     public void start() {
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
-        mWarnings = Dependency.get(WarningsUI.class);
-        mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
         mLastConfiguration.setTo(mContext.getResources().getConfiguration());
 
         ContentObserver obs = new ContentObserver(mHandler) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 1dba536..ded6ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -85,6 +85,7 @@
     private final QSPanelController mQsPanelController;
     private final QuickQSPanelController mQuickQSPanelController;
     private final QuickStatusBarHeader mQuickStatusBarHeader;
+    private final QSFgsManagerFooter mFgsManagerFooter;
     private final QSSecurityFooter mSecurityFooter;
     private final QS mQs;
     private final View mQSFooterActions;
@@ -151,7 +152,8 @@
     public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
             QSPanelController qsPanelController,
             QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
-            QSSecurityFooter securityFooter, @Main Executor executor, TunerService tunerService,
+            QSFgsManagerFooter fgsManagerFooter, QSSecurityFooter securityFooter,
+            @Main Executor executor, TunerService tunerService,
             QSExpansionPathInterpolator qsExpansionPathInterpolator,
             @Named(QS_FOOTER) FooterActionsView qsFooterActionsView,
             @Named(QQS_FOOTER) FooterActionsView qqsFooterActionsView) {
@@ -162,6 +164,7 @@
         mQuickStatusBarHeader = quickStatusBarHeader;
         mQQSFooterActions = qqsFooterActionsView;
         mQSFooterActions = qsFooterActionsView;
+        mFgsManagerFooter = fgsManagerFooter;
         mSecurityFooter = securityFooter;
         mHost = qsTileHost;
         mExecutor = executor;
@@ -481,6 +484,7 @@
 
             // Fade in the security footer and the divider as we reach the final position
             Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
+            builder.addFloat(mFgsManagerFooter.getView(), "alpha", 0, 1);
             builder.addFloat(mSecurityFooter.getView(), "alpha", 0, 1);
             if (mQsPanelController.shouldUseHorizontalLayout()
                     && mQsPanelController.mMediaHost.hostView != null) {
@@ -490,6 +494,7 @@
                 mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
             }
             mAllPagesDelayedAnimator = builder.build();
+            mAllViews.add(mFgsManagerFooter.getView());
             mAllViews.add(mSecurityFooter.getView());
             translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
             qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
new file mode 100644
index 0000000..082de16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.qs;
+
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
+
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FGS_MANAGER_FOOTER_VIEW;
+
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.fgsmanager.FgsManagerDialogFactory;
+import com.android.systemui.statusbar.policy.RunningFgsController;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Footer entry point for the foreground service manager
+ */
+public class QSFgsManagerFooter implements View.OnClickListener {
+
+    private final View mRootView;
+    private final TextView mFooterText;
+    private final Context mContext;
+    private final Executor mMainExecutor;
+    private final Executor mExecutor;
+    private final RunningFgsController mRunningFgsController;
+    private final FgsManagerDialogFactory mFgsManagerDialogFactory;
+
+    private boolean mIsInitialized = false;
+    private boolean mIsAvailable = false;
+
+    @Inject
+    QSFgsManagerFooter(@Named(QS_FGS_MANAGER_FOOTER_VIEW) View rootView,
+            @Main Executor mainExecutor, RunningFgsController runningFgsController,
+            @Background Executor executor,
+            FgsManagerDialogFactory fgsManagerDialogFactory) {
+        mRootView = rootView;
+        mFooterText = mRootView.findViewById(R.id.footer_text);
+        ImageView icon = mRootView.findViewById(R.id.primary_footer_icon);
+        icon.setImageResource(R.drawable.ic_info_outline);
+        mContext = rootView.getContext();
+        mMainExecutor = mainExecutor;
+        mExecutor = executor;
+        mRunningFgsController = runningFgsController;
+        mFgsManagerDialogFactory = fgsManagerDialogFactory;
+    }
+
+    public void init() {
+        if (mIsInitialized) {
+            return;
+        }
+
+        mRootView.setOnClickListener(this);
+
+        mRunningFgsController.addCallback(packages -> refreshState());
+
+        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI, mExecutor,
+                (DeviceConfig.OnPropertiesChangedListener) properties -> {
+                    mIsAvailable = properties.getBoolean(TASK_MANAGER_ENABLED, mIsAvailable);
+                });
+        mIsAvailable = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, false);
+
+        mIsInitialized = true;
+    }
+
+    @Override
+    public void onClick(View view) {
+        mFgsManagerDialogFactory.create(mRootView);
+    }
+
+    public void refreshState() {
+        mExecutor.execute(this::handleRefreshState);
+    }
+
+    public View getView() {
+        return mRootView;
+    }
+
+    private boolean isAvailable() {
+        return mIsAvailable;
+    }
+
+    public void handleRefreshState() {
+        int numPackages = mRunningFgsController.getPackagesWithFgs().size();
+        mMainExecutor.execute(() -> {
+            mFooterText.setText(mContext.getResources().getQuantityString(
+                    R.plurals.fgs_manager_footer_label, numPackages, numPackages));
+            mRootView.setVisibility(numPackages > 0 && isAvailable() ? View.VISIBLE : View.GONE);
+        });
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 38061a8..6b515c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -86,6 +86,8 @@
             new ArrayList<>();
 
     @Nullable
+    protected View mFgsManagerFooter;
+    @Nullable
     protected View mSecurityFooter;
 
     @Nullable
@@ -448,7 +450,12 @@
             switchToParent(mSecurityFooter, mHeaderContainer, 0);
         } else {
             // Add after the footer
-            int index = indexOfChild(mFooter);
+            int index;
+            if (mFgsManagerFooter != null) {
+                index = indexOfChild(mFgsManagerFooter);
+            } else {
+                index = indexOfChild(mFooter);
+            }
             switchToParent(mSecurityFooter, this, index + 1);
         }
     }
@@ -722,6 +729,17 @@
         switchSecurityFooter(shouldUseSplitNotificationShade);
     }
 
+    /**
+     * Set the fgs manager footer view and switch it into the right place
+     * @param view the view in question
+     */
+    public void setFgsManagerFooter(View view) {
+        mFgsManagerFooter = view;
+        // Add after the footer
+        int index = indexOfChild(mFooter);
+        switchToParent(mFgsManagerFooter, this, index + 1);
+    }
+
     protected void setPageMargin(int pageMargin) {
         if (mTileLayout instanceof PagedTileLayout) {
             ((PagedTileLayout) mTileLayout).setPageMargin(pageMargin);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 001c740e..cbfe944 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -57,6 +57,7 @@
 public class QSPanelController extends QSPanelControllerBase<QSPanel> {
     public static final String QS_REMOVE_LABELS = "sysui_remove_labels";
 
+    private final QSFgsManagerFooter mQSFgsManagerFooter;
     private final QSSecurityFooter mQsSecurityFooter;
     private final TunerService mTunerService;
     private final QSCustomizerController mQsCustomizerController;
@@ -94,7 +95,8 @@
     };
 
     @Inject
-    QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService,
+    QSPanelController(QSPanel view, QSFgsManagerFooter qsFgsManagerFooter,
+            QSSecurityFooter qsSecurityFooter, TunerService tunerService,
             QSTileHost qstileHost, QSCustomizerController qsCustomizerController,
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QS_PANEL) MediaHost mediaHost,
@@ -105,6 +107,7 @@
             FalsingManager falsingManager, CommandQueue commandQueue) {
         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
                 metricsLogger, uiEventLogger, qsLogger, dumpManager);
+        mQSFgsManagerFooter = qsFgsManagerFooter;
         mQsSecurityFooter = qsSecurityFooter;
         mTunerService = tunerService;
         mQsCustomizerController = qsCustomizerController;
@@ -128,6 +131,7 @@
         mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
         mQsCustomizerController.init();
         mBrightnessSliderController.init();
+        mQSFgsManagerFooter.init();
     }
 
     private void updateMediaExpansion() {
@@ -146,6 +150,7 @@
             refreshAllTiles();
         }
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
+        mView.setFgsManagerFooter(mQSFgsManagerFooter.getView());
         mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade);
         switchTileLayout(true);
         mBrightnessMirrorHandler.onQsPanelAttached();
@@ -230,6 +235,7 @@
     public void refreshAllTiles() {
         mBrightnessController.checkRestrictionAndSetEnabled();
         super.refreshAllTiles();
+        mQSFgsManagerFooter.refreshState();
         mQsSecurityFooter.refreshState();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index d3bad16..90cf92a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -181,6 +181,7 @@
     }
 
     private void clearAccessibilityState() {
+        mNeedsFocus = false;
         if (mAccessibilityAction == ACTION_ADD) {
             // Remove blank tile from last spot
             mTiles.remove(--mEditIndex);
@@ -415,9 +416,6 @@
                         int oldLeft, int oldTop, int oldRight, int oldBottom) {
                     holder.mTileView.removeOnLayoutChangeListener(this);
                     holder.mTileView.requestAccessibilityFocus();
-                    if (mAccessibilityAction == ACTION_NONE) {
-                        holder.mTileView.clearAccessibilityFocus();
-                    }
                 }
             });
             mNeedsFocus = false;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 11e5b6e..1958caf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -53,6 +53,7 @@
  */
 @Module
 public interface QSFragmentModule {
+    String QS_FGS_MANAGER_FOOTER_VIEW = "qs_fgs_manager_footer";
     String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
     String QQS_FOOTER = "qqs_footer";
     String QS_FOOTER = "qs_footer";
@@ -205,4 +206,15 @@
     static StatusIconContainer providesStatusIconContainer(QuickStatusBarHeader qsHeader) {
         return qsHeader.findViewById(R.id.statusIcons);
     }
+
+    /** */
+    @Provides
+    @QSScope
+    @Named(QS_FGS_MANAGER_FOOTER_VIEW)
+    static View providesQSFgsManagerFooterView(
+            @QSThemedContext LayoutInflater layoutInflater,
+            QSPanel qsPanel
+    ) {
+        return layoutInflater.inflate(R.layout.quick_settings_security_footer, qsPanel, false);
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 5e68f61..86fc4de 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -39,7 +39,6 @@
 import com.android.systemui.qs.tiles.DataSaverTile;
 import com.android.systemui.qs.tiles.DeviceControlsTile;
 import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.qs.tiles.FgsManagerTile;
 import com.android.systemui.qs.tiles.FlashlightTile;
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.InternetTile;
@@ -99,7 +98,6 @@
     private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider;
     private final Provider<QRCodeScannerTile> mQRCodeScannerTileProvider;
     private final Provider<OneHandedModeTile> mOneHandedModeTileProvider;
-    private final Provider<FgsManagerTile> mFgsManagerTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
     private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -137,7 +135,6 @@
             Provider<QuickAccessWalletTile> quickAccessWalletTileProvider,
             Provider<QRCodeScannerTile> qrCodeScannerTileProvider,
             Provider<OneHandedModeTile> oneHandedModeTileProvider,
-            Provider<FgsManagerTile> fgsManagerTileProvider,
             Provider<ColorCorrectionTile> colorCorrectionTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
@@ -171,7 +168,6 @@
         mQuickAccessWalletTileProvider = quickAccessWalletTileProvider;
         mQRCodeScannerTileProvider = qrCodeScannerTileProvider;
         mOneHandedModeTileProvider = oneHandedModeTileProvider;
-        mFgsManagerTileProvider = fgsManagerTileProvider;
         mColorCorrectionTileProvider = colorCorrectionTileProvider;
     }
 
@@ -246,8 +242,6 @@
                 return mQRCodeScannerTileProvider.get();
             case "onehanded":
                 return mOneHandedModeTileProvider.get();
-            case "fgsmanager":
-                return mFgsManagerTileProvider.get();
             case "color_correction":
                 return mColorCorrectionTileProvider.get();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 7efb983..821dfa5f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -653,7 +653,6 @@
         "qr_code_scanner" to R.array.tile_states_qr_code_scanner,
         "alarm" to R.array.tile_states_alarm,
         "onehanded" to R.array.tile_states_onehanded,
-        "fgsmanager" to R.array.tile_states_fgsmanager,
         "color_correction" to R.array.tile_states_color_correction
     )
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FgsManagerTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FgsManagerTile.kt
deleted file mode 100644
index 939a297..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FgsManagerTile.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.qs.tiles
-
-import android.content.Intent
-import android.os.Handler
-import android.os.Looper
-import android.provider.DeviceConfig
-import android.view.View
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
-import com.android.internal.logging.MetricsLogger
-import com.android.systemui.DejankUtils
-import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.fgsmanager.FgsManagerDialogFactory
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.plugins.qs.QSTile
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.qs.QSHost
-import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.statusbar.policy.RunningFgsController
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/**
- * Quicksettings tile for the foreground services manager (task manager)
- */
-class FgsManagerTile @Inject constructor(
-    host: QSHost?,
-    @Background backgroundLooper: Looper?,
-    @Background private val backgroundExecutor: Executor?,
-    @Main mainHandler: Handler?,
-    falsingManager: FalsingManager?,
-    metricsLogger: MetricsLogger?,
-    statusBarStateController: StatusBarStateController?,
-    activityStarter: ActivityStarter?,
-    qsLogger: QSLogger?,
-    private val fgsManagerDialogFactory: FgsManagerDialogFactory,
-    private val runningFgsController: RunningFgsController
-) : QSTileImpl<QSTile.State>(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
-        statusBarStateController, activityStarter, qsLogger), RunningFgsController.Callback {
-
-    override fun handleInitialize() {
-        super.handleInitialize()
-        mUiHandler.post { runningFgsController.observe(lifecycle, this) }
-    }
-
-    override fun isAvailable(): Boolean {
-        return DejankUtils.whitelistIpcs<Boolean> {
-            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                    SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, false)
-        }
-    }
-
-    override fun newTileState(): QSTile.State {
-        return QSTile.State()
-    }
-
-    override fun handleClick(view: View?) {
-        mUiHandler.post { fgsManagerDialogFactory.create(view) }
-    }
-
-    override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
-        state?.label = tileLabel
-        state?.secondaryLabel = runningFgsController.getPackagesWithFgs().size.toString()
-        state?.handlesLongClick = false
-        state?.icon = ResourceIcon.get(R.drawable.ic_list)
-    }
-
-    override fun getMetricsCategory(): Int = 0
-
-    override fun getLongClickIntent(): Intent? = null
-
-    // Inline the string so we don't waste translator time since this isn't used in the mocks.
-    // TODO If mocks change need to remember to move this to strings.xml
-    override fun getTileLabel(): CharSequence = "Active apps"
-
-    override fun onFgsPackagesChanged(packages: List<UserPackageTime>) = refreshState()
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index d7d1de0..991a68f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -398,6 +398,11 @@
             min = mBrightnessMin;
             max = mBrightnessMax;
         }
+
+        // Ensure the slider is in a fixed position first, then check if we should animate.
+        if (mSliderAnimator != null && mSliderAnimator.isStarted()) {
+            mSliderAnimator.cancel();
+        }
         // convertGammaToLinearFloat returns 0-1
         if (BrightnessSynchronizer.floatEquals(brightnessValue,
                 convertGammaToLinearFloat(mControl.getValue(), min, max))) {
@@ -420,9 +425,6 @@
             mControl.setValue(target);
             mControlValueInitialized = true;
         }
-        if (mSliderAnimator != null && mSliderAnimator.isStarted()) {
-            mSliderAnimator.cancel();
-        }
         mSliderAnimator = ValueAnimator.ofInt(mControl.getValue(), target);
         mSliderAnimator.addUpdateListener((ValueAnimator animation) -> {
             mExternalChange = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 963a0d7..6335f88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -151,6 +151,7 @@
     private boolean mPowerPluggedIn;
     private boolean mPowerPluggedInWired;
     private boolean mPowerPluggedInWireless;
+    private boolean mPowerPluggedInDock;
     private boolean mPowerCharged;
     private boolean mBatteryOverheated;
     private boolean mEnableBatteryDefender;
@@ -786,6 +787,10 @@
             chargingId = hasChargingTime
                     ? R.string.keyguard_indication_charging_time_wireless
                     : R.string.keyguard_plugged_in_wireless;
+        } else if (mPowerPluggedInDock) {
+            chargingId = hasChargingTime
+                    ? R.string.keyguard_indication_charging_time_dock
+                    : R.string.keyguard_plugged_in_dock;
         } else {
             chargingId = hasChargingTime
                     ? R.string.keyguard_indication_charging_time
@@ -911,6 +916,7 @@
             boolean wasPluggedIn = mPowerPluggedIn;
             mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
             mPowerPluggedInWireless = status.isPluggedInWireless() && isChargingOrFull;
+            mPowerPluggedInDock = status.isPluggedInDock() && isChargingOrFull;
             mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
             mPowerCharged = status.isCharged();
             mChargingWattage = status.maxChargingWattage;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt
index 03b978e..68bdd18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/SectionHeaderVisibilityProvider.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.statusbar.notification
 
+import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.R
 import javax.inject.Inject
 
 /**
@@ -29,6 +31,10 @@
  * visibility when it invalidates, and we just store that state here.)
  */
 @SysUISingleton
-class SectionHeaderVisibilityProvider @Inject constructor() {
+class SectionHeaderVisibilityProvider @Inject constructor(
+    context: Context
+) {
+    var neverShowSectionHeaders = context.resources.getBoolean(R.bool.config_notification_never_show_section_headers)
+        private set
     var sectionHeadersVisible = true
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 733be9c..0ce07cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -220,8 +220,10 @@
     }
 
     private void invalidateListFromFilter(String reason) {
-        mSectionHeaderVisibilityProvider.setSectionHeadersVisible(
-                mStatusBarStateController.getState() != StatusBarState.KEYGUARD);
+        boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+        boolean neverShowSections = mSectionHeaderVisibilityProvider.getNeverShowSectionHeaders();
+        boolean showSections = !onKeyguard && !neverShowSections;
+        mSectionHeaderVisibilityProvider.setSectionHeadersVisible(showSections);
         mNotifFilter.invalidateList();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 769f689..e59c99a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3928,6 +3928,15 @@
         mKeyguardStatusViewController.animateFoldToAod();
     }
 
+    /**
+     * Cancels fold to AOD transition and resets view state
+     */
+    public void cancelFoldToAodAnimation() {
+        cancelAnimation();
+        resetAlpha();
+        resetTranslation();
+    }
+
     /** */
     public void setImportantForAccessibility(int mode) {
         mView.setImportantForAccessibility(mode);
@@ -4046,6 +4055,10 @@
         mView.setTranslationX(0f);
     }
 
+    public void resetAlpha() {
+        mView.setAlpha(1f);
+    }
+
     public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
         return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
                 durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction(
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 455ffdc..d3f2794 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2998,7 +2998,7 @@
     }
 
     private void onLaunchTransitionFadingEnded() {
-        mNotificationPanelViewController.setAlpha(1.0f);
+        mNotificationPanelViewController.resetAlpha();
         mNotificationPanelViewController.onAffordanceLaunchEnded();
         releaseGestureWakeLock();
         runLaunchTransitionEndRunnable();
@@ -3029,7 +3029,7 @@
             }
             updateScrimController();
             mPresenter.updateMediaMetaData(false, true);
-            mNotificationPanelViewController.setAlpha(1);
+            mNotificationPanelViewController.resetAlpha();
             mNotificationPanelViewController.fadeOut(
                     FADE_KEYGUARD_START_DELAY, FADE_KEYGUARD_DURATION,
                     this::onLaunchTransitionFadingEnded);
@@ -3130,7 +3130,7 @@
         releaseGestureWakeLock();
         mNotificationPanelViewController.onAffordanceLaunchEnded();
         mNotificationPanelViewController.cancelAnimation();
-        mNotificationPanelViewController.setAlpha(1f);
+        mNotificationPanelViewController.resetAlpha();
         mNotificationPanelViewController.resetTranslation();
         mNotificationPanelViewController.resetViewGroupFade();
         updateDozingState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 59969c0..5e91a25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -30,6 +30,7 @@
 import android.content.PermissionChecker;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.database.ContentObserver;
 import android.location.LocationManager;
 import android.os.Handler;
 import android.os.Looper;
@@ -43,6 +44,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.BootCompleteCache;
 import com.android.systemui.appops.AppOpItem;
 import com.android.systemui.appops.AppOpsController;
@@ -53,6 +56,7 @@
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.Utils;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -71,30 +75,48 @@
     private final DeviceConfigProxy mDeviceConfigProxy;
     private final BootCompleteCache mBootCompleteCache;
     private final UserTracker mUserTracker;
+    private final UiEventLogger mUiEventLogger;
     private final H mHandler;
     private final Handler mBackgroundHandler;
     private final PackageManager mPackageManager;
+    private final ContentObserver mContentObserver;
+    private final SecureSettings mSecureSettings;
 
     private boolean mAreActiveLocationRequests;
     private boolean mShouldDisplayAllAccesses;
-    private boolean mShowSystemAccesses;
+    private boolean mShowSystemAccessesFlag;
+    private boolean mShowSystemAccessesSetting;
 
     @Inject
     public LocationControllerImpl(Context context, AppOpsController appOpsController,
             DeviceConfigProxy deviceConfigProxy,
             @Main Looper mainLooper, @Background Handler backgroundHandler,
             BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache,
-            UserTracker userTracker, PackageManager packageManager) {
+            UserTracker userTracker, PackageManager packageManager, UiEventLogger uiEventLogger,
+            SecureSettings secureSettings) {
         mContext = context;
         mAppOpsController = appOpsController;
         mDeviceConfigProxy = deviceConfigProxy;
         mBootCompleteCache = bootCompleteCache;
         mHandler = new H(mainLooper);
         mUserTracker = userTracker;
+        mUiEventLogger = uiEventLogger;
+        mSecureSettings = secureSettings;
         mBackgroundHandler = backgroundHandler;
         mPackageManager = packageManager;
         mShouldDisplayAllAccesses = getAllAccessesSetting();
-        mShowSystemAccesses = getShowSystemSetting();
+        mShowSystemAccessesFlag = getShowSystemFlag();
+        mShowSystemAccessesSetting = getShowSystemSetting();
+        mContentObserver = new ContentObserver(mBackgroundHandler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                mShowSystemAccessesSetting = getShowSystemSetting();
+            }
+        };
+
+        // Register to listen for changes in Settings.Secure settings.
+        mSecureSettings.registerContentObserver(
+                Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, mContentObserver);
 
         // Register to listen for changes in DeviceConfig settings.
         mDeviceConfigProxy.addOnPropertiesChangedListener(
@@ -102,7 +124,7 @@
                 backgroundHandler::post,
                 properties -> {
                     mShouldDisplayAllAccesses = getAllAccessesSetting();
-                    mShowSystemAccesses = getShowSystemSetting();
+                    mShowSystemAccessesFlag = getShowSystemSetting();
                     updateActiveLocationRequests();
                 });
 
@@ -191,10 +213,15 @@
                 SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false);
     }
 
-    private boolean getShowSystemSetting() {
+    private boolean getShowSystemFlag() {
         return mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SHOW_SYSTEM, false);
     }
+
+    private boolean getShowSystemSetting() {
+        return mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1;
+    }
+
     /**
      * Returns true if there currently exist active high power location requests.
      */
@@ -222,6 +249,10 @@
         }
         boolean hadActiveLocationRequests = mAreActiveLocationRequests;
         boolean shouldDisplay = false;
+        boolean showSystem = mShowSystemAccessesFlag || mShowSystemAccessesSetting;
+        boolean systemAppOp = false;
+        boolean nonSystemAppOp = false;
+        boolean isSystemApp;
 
         List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
         final List<UserInfo> profiles = mUserTracker.getUserProfiles();
@@ -229,18 +260,38 @@
         for (int i = 0; i < numItems; i++) {
             if (appOpsItems.get(i).getCode() == OP_FINE_LOCATION
                     || appOpsItems.get(i).getCode() == OP_COARSE_LOCATION) {
-                if (mShowSystemAccesses) {
-                    shouldDisplay = true;
+                isSystemApp = isSystemApp(profiles, appOpsItems.get(i));
+                if (isSystemApp) {
+                    systemAppOp = true;
                 } else {
-                    shouldDisplay |= !isSystemApp(profiles, appOpsItems.get(i));
+                    nonSystemAppOp = true;
                 }
+
+                shouldDisplay = showSystem || shouldDisplay || !isSystemApp;
             }
         }
 
-        mAreActiveLocationRequests = areActiveHighPowerLocationRequests() || shouldDisplay;
+        boolean highPowerOp = areActiveHighPowerLocationRequests();
+        mAreActiveLocationRequests = highPowerOp || shouldDisplay;
         if (mAreActiveLocationRequests != hadActiveLocationRequests) {
             mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
         }
+
+        // Log each of the types of location access that would cause the location indicator to be
+        // shown, regardless of device's setting state. This is used to understand how often a
+        // user would see the location indicator based on any settings state the device could be in.
+        if (!hadActiveLocationRequests && (highPowerOp || systemAppOp || nonSystemAppOp)) {
+            if (highPowerOp) {
+                mUiEventLogger.log(
+                        LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER);
+            }
+            if (systemAppOp) {
+                mUiEventLogger.log(LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP);
+            }
+            if (nonSystemAppOp) {
+                mUiEventLogger.log(LocationIndicatorEvent.LOCATION_INDICATOR_NON_SYSTEM_APP);
+            }
+        }
     }
 
     private boolean isSystemApp(List<UserInfo> profiles, AppOpItem item) {
@@ -283,6 +334,11 @@
             mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
             if (mAreActiveLocationRequests != hadActiveLocationRequests) {
                 mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
+                if (mAreActiveLocationRequests) {
+                    // Log that the indicator was shown for a high power op.
+                    mUiEventLogger.log(
+                            LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER);
+                }
             }
         }
     }
@@ -341,4 +397,24 @@
                     cb -> cb.onLocationSettingsChanged(isEnabled));
         }
     }
-}
+
+    /**
+     * Enum for events which prompt the location indicator to appear.
+     */
+    enum LocationIndicatorEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Location indicator shown for high power access")
+        LOCATION_INDICATOR_MONITOR_HIGH_POWER(935),
+        @UiEvent(doc = "Location indicator shown for system app access")
+        LOCATION_INDICATOR_SYSTEM_APP(936),
+        @UiEvent(doc = "Location indicator shown for non system app access")
+        LOCATION_INDICATOR_NON_SYSTEM_APP(937);
+
+        private final int mId;
+        LocationIndicatorEvent(int id) {
+            mId = id;
+        }
+        @Override public int getId() {
+            return mId;
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
index e25a105..c199744 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
@@ -25,7 +25,6 @@
 import com.android.internal.messages.nano.SystemMessageProto
 import com.android.internal.net.VpnConfig
 import com.android.systemui.CoreStartable
-import com.android.systemui.Dependency
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.policy.SecurityController
@@ -35,12 +34,13 @@
  * Observes if a vpn connection is active and displays a notification to the user
  */
 @SysUISingleton
-class VpnStatusObserver @Inject constructor(context: Context) : CoreStartable(context),
+class VpnStatusObserver @Inject constructor(
+    context: Context,
+    private val securityController: SecurityController
+) : CoreStartable(context),
         SecurityController.SecurityControllerCallback {
 
     private var vpnConnected = false
-    private val securityController: SecurityController =
-            Dependency.get(SecurityController::class.java)
     private val notificationManager = NotificationManager.from(context)
     private val notificationChannel = createNotificationChannel()
     private val vpnConnectedNotificationBuilder = createVpnConnectedNotificationBuilder()
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index aaf35af..c481fc9 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.unfold
 
+import android.os.Handler
 import android.os.PowerManager
 import android.provider.Settings
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.statusbar.LightRevealScrim
@@ -37,6 +39,7 @@
 class FoldAodAnimationController
 @Inject
 constructor(
+    @Main private val handler: Handler,
     private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
     private val wakefulnessLifecycle: WakefulnessLifecycle,
     private val globalSettings: GlobalSettings
@@ -50,6 +53,14 @@
     private var shouldPlayAnimation = false
     private val statusListeners = arrayListOf<FoldAodAnimationStatus>()
 
+    private val startAnimationRunnable = Runnable {
+        statusBar.notificationPanelViewController.startFoldToAodAnimation {
+            // End action
+            isAnimationPlaying = false
+            keyguardViewMediatorLazy.get().maybeHandlePendingLock()
+        }
+    }
+
     private var isAnimationPlaying = false
 
     override fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) {
@@ -79,6 +90,11 @@
         }
 
     override fun onStartedWakingUp() {
+        if (isAnimationPlaying) {
+            handler.removeCallbacks(startAnimationRunnable)
+            statusBar.notificationPanelViewController.cancelFoldToAodAnimation();
+        }
+
         shouldPlayAnimation = false
         isAnimationPlaying = false
     }
@@ -115,11 +131,10 @@
 
     fun onScreenTurnedOn() {
         if (shouldPlayAnimation) {
-            statusBar.notificationPanelViewController.startFoldToAodAnimation {
-                // End action
-                isAnimationPlaying = false
-                keyguardViewMediatorLazy.get().maybeHandlePendingLock()
-            }
+            handler.removeCallbacks(startAnimationRunnable)
+
+            // Post starting the animation to the next frame to avoid junk due to inset changes
+            handler.post(startAnimationRunnable)
             shouldPlayAnimation = false
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
index be5e0a0..089650c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
@@ -26,8 +26,6 @@
 
 import androidx.core.content.FileProvider;
 
-import com.android.systemui.Dependency;
-
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -35,7 +33,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -53,12 +50,14 @@
     private static final int BUFSIZ = 1024 * 1024; // 1MB
 
     private final Context context;
+    private GarbageMonitor mGarbageMonitor;
     private Uri hprofUri;
     private long rss;
     final StringBuilder body = new StringBuilder();
 
-    public DumpTruck(Context context) {
+    public DumpTruck(Context context, GarbageMonitor garbageMonitor) {
         this.context = context;
+        mGarbageMonitor = garbageMonitor;
     }
 
     /**
@@ -68,8 +67,6 @@
      * @return this, for chaining
      */
     public DumpTruck captureHeaps(List<Long> pids) {
-        final GarbageMonitor gm = Dependency.get(GarbageMonitor.class);
-
         final File dumpDir = new File(context.getCacheDir(), FILEPROVIDER_PATH);
         dumpDir.mkdirs();
         hprofUri = null;
@@ -83,16 +80,14 @@
         for (Long pidL : pids) {
             final int pid = pidL.intValue();
             body.append("  pid ").append(pid);
-            if (gm != null) {
-                GarbageMonitor.ProcessMemInfo info = gm.getMemInfo(pid);
-                if (info != null) {
-                    body.append(":")
-                            .append(" up=")
-                            .append(info.getUptime())
-                            .append(" rss=")
-                            .append(info.currentRss);
-                    rss = info.currentRss;
-                }
+            GarbageMonitor.ProcessMemInfo info = mGarbageMonitor.getMemInfo(pid);
+            if (info != null) {
+                body.append(":")
+                        .append(" up=")
+                        .append(info.getUptime())
+                        .append(" rss=")
+                        .append(info.currentRss);
+                rss = info.currentRss;
             }
             if (pid == myPid) {
                 final String path =
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index 612b7cb..9fed158 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -150,7 +150,7 @@
         mTrackedGarbage = leakDetector.getTrackedGarbage();
         mLeakReporter = leakReporter;
 
-        mDumpTruck = new DumpTruck(mContext);
+        mDumpTruck = new DumpTruck(mContext, this);
 
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
 
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 31b17f8..6fefce2 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -41,7 +41,6 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.Dependency;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.WMComponent;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -125,6 +124,7 @@
     private final SysUiState mSysUiState;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final ProtoTracer mProtoTracer;
+    private final UserInfoController mUserInfoController;
     private final Executor mSysUiMainExecutor;
 
     private boolean mIsSysUiStateValid;
@@ -153,6 +153,7 @@
             SysUiState sysUiState,
             ProtoTracer protoTracer,
             WakefulnessLifecycle wakefulnessLifecycle,
+            UserInfoController userInfoController,
             @Main Executor sysUiMainExecutor) {
         super(context);
         mCommandQueue = commandQueue;
@@ -171,6 +172,7 @@
         mShellCommandHandler = shellCommandHandler;
         mCompatUIOptional = sizeCompatUIOptional;
         mDragAndDropOptional = dragAndDropOptional;
+        mUserInfoController = userInfoController;
         mSysUiMainExecutor = sysUiMainExecutor;
     }
 
@@ -231,8 +233,7 @@
         });
 
         // The media session listener needs to be re-registered when switching users
-        UserInfoController userInfoController = Dependency.get(UserInfoController.class);
-        userInfoController.addCallback((String name, Drawable picture, String userAccount) ->
+        mUserInfoController.addCallback((String name, Drawable picture, String userAccount) ->
                 pip.registerSessionListenerForCurrentUser());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 0b399cf..ae1268d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -56,6 +56,7 @@
 import android.widget.ScrollView;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -75,6 +76,7 @@
 
     private @Mock AuthDialogCallback mCallback;
     private @Mock UserManager mUserManager;
+    private @Mock WakefulnessLifecycle mWakefulnessLifecycle;
 
     @Before
     public void setup() {
@@ -263,15 +265,17 @@
                 componentInfo,
                 FingerprintSensorProperties.TYPE_REAR,
                 false /* resetLockoutRequiresHardwareAuthToken */));
-        mAuthContainer = new TestableAuthContainer(config, fpProps, null /* faceProps */);
+        mAuthContainer = new TestableAuthContainer(config, fpProps, null /* faceProps */,
+                mWakefulnessLifecycle);
     }
 
     private class TestableAuthContainer extends AuthContainerView {
         TestableAuthContainer(AuthContainerView.Config config,
                 @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
-                @Nullable List<FaceSensorPropertiesInternal> faceProps) {
+                @Nullable List<FaceSensorPropertiesInternal> faceProps,
+                WakefulnessLifecycle wakefulnessLifecycle) {
 
-            super(config, new MockInjector(), fpProps, faceProps);
+            super(config, new MockInjector(), fpProps, faceProps, wakefulnessLifecycle);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 08c7714..786f547 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -69,6 +69,7 @@
 
 import com.android.internal.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.util.concurrency.Execution;
 import com.android.systemui.util.concurrency.FakeExecution;
@@ -117,6 +118,8 @@
     private SidefpsController mSidefpsController;
     @Mock
     private DisplayManager mDisplayManager;
+    @Mock
+    private WakefulnessLifecycle mWakefulnessLifecycle;
     @Captor
     ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
     @Captor
@@ -677,14 +680,15 @@
                 Provider<SidefpsController> sidefpsControllerFactory) {
             super(context, execution, commandQueue, activityTaskManager, windowManager,
                     fingerprintManager, faceManager, udfpsControllerFactory,
-                    sidefpsControllerFactory, mDisplayManager, mHandler);
+                    sidefpsControllerFactory, mDisplayManager, mWakefulnessLifecycle, mHandler);
         }
 
         @Override
         protected AuthDialog buildDialog(PromptInfo promptInfo,
                 boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed,
                 String opPackageName, boolean skipIntro, long operationId, long requestId,
-                @BiometricManager.BiometricMultiSensorMode int multiSensorConfig) {
+                @BiometricManager.BiometricMultiSensorMode int multiSensorConfig,
+                WakefulnessLifecycle wakefulnessLifecycle) {
 
             mLastBiometricPromptInfo = promptInfo;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 89c0712..421ae03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -100,7 +100,7 @@
     public void getItemCount_zeroMode_containExtraOneForPairNew() {
         when(mMediaOutputController.isZeroMode()).thenReturn(true);
 
-        assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size());
+        assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index e73e5ff..721809c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.when;
 
 import android.content.BroadcastReceiver;
-import android.content.Context;
 import android.content.IntentFilter;
 import android.os.BatteryManager;
 import android.os.Handler;
@@ -81,9 +80,9 @@
     private static final int OLD_BATTERY_LEVEL_10 = 10;
     private static final long VERY_BELOW_SEVERE_HYBRID_THRESHOLD = TimeUnit.MINUTES.toMillis(15);
     public static final int BATTERY_LEVEL_10 = 10;
-    private WarningsUI mMockWarnings;
+    @Mock private WarningsUI mMockWarnings;
     private PowerUI mPowerUI;
-    private EnhancedEstimates mEnhancedEstimates;
+    @Mock private EnhancedEstimates mEnhancedEstimates;
     @Mock private PowerManager mPowerManager;
     @Mock private IThermalService mThermalServiceMock;
     private IThermalEventListener mUsbThermalEventListener;
@@ -96,13 +95,9 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
-        mEnhancedEstimates = mDependency.injectMockDependency(EnhancedEstimates.class);
 
         when(mStatusBarOptionalLazy.get()).thenReturn(Optional.of(mStatusBar));
 
-        mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);
-
         createPowerUi();
         mSkinThermalEventListener = mPowerUI.new SkinThermalEventListener();
         mUsbThermalEventListener = mPowerUI.new UsbThermalEventListener();
@@ -690,7 +685,8 @@
 
     private void createPowerUi() {
         mPowerUI = new PowerUI(
-                mContext, mBroadcastDispatcher, mCommandQueue, mStatusBarOptionalLazy);
+                mContext, mBroadcastDispatcher, mCommandQueue, mStatusBarOptionalLazy,
+                mMockWarnings, mEnhancedEstimates, mPowerManager);
         mPowerUI.mThermalService = mThermalServiceMock;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index 3242adb..b5ce706 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -80,6 +80,8 @@
     @Mock
     private TunerService mTunerService;
     @Mock
+    private QSFgsManagerFooter mQSFgsManagerFooter;
+    @Mock
     private QSSecurityFooter mQSSecurityFooter;
     @Mock
     private QSLogger mQSLogger;
@@ -127,8 +129,8 @@
                 .thenReturn(mQSTileRevealController);
         when(mMediaHost.getDisappearParameters()).thenReturn(new DisappearParameters());
 
-        mController = new QSPanelController(mQSPanel, mQSSecurityFooter, mTunerService,
-                mQSTileHost, mQSCustomizerController, true, mMediaHost,
+        mController = new QSPanelController(mQSPanel, mQSFgsManagerFooter, mQSSecurityFooter,
+                mTunerService, mQSTileHost, mQSCustomizerController, true, mMediaHost,
                 mQSTileRevealControllerFactory, mDumpManager, mMetricsLogger, mUiEventLogger,
                 mQSLogger, mBrightnessControllerFactory, mToggleSliderViewControllerFactory,
                 mFalsingManager, mCommandQueue
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
index 968b12a..88b133e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
@@ -34,7 +34,6 @@
 import com.android.systemui.qs.tiles.DataSaverTile
 import com.android.systemui.qs.tiles.DeviceControlsTile
 import com.android.systemui.qs.tiles.DndTile
-import com.android.systemui.qs.tiles.FgsManagerTile
 import com.android.systemui.qs.tiles.FlashlightTile
 import com.android.systemui.qs.tiles.HotspotTile
 import com.android.systemui.qs.tiles.InternetTile
@@ -92,7 +91,6 @@
         "wallet" to QuickAccessWalletTile::class.java,
         "qr_code_scanner" to QRCodeScannerTile::class.java,
         "onehanded" to OneHandedModeTile::class.java,
-        "fgsmanager" to FgsManagerTile::class.java,
         "color_correction" to ColorCorrectionTile::class.java
 )
 
@@ -133,7 +131,6 @@
     @Mock private lateinit var quickAccessWalletTile: QuickAccessWalletTile
     @Mock private lateinit var qrCodeScannerTile: QRCodeScannerTile
     @Mock private lateinit var oneHandedModeTile: OneHandedModeTile
-    @Mock private lateinit var fgsManagerTile: FgsManagerTile
     @Mock private lateinit var colorCorrectionTile: ColorCorrectionTile
 
     private lateinit var factory: QSFactoryImpl
@@ -178,7 +175,6 @@
                 { quickAccessWalletTile },
                 { qrCodeScannerTile },
                 { oneHandedModeTile },
-                { fgsManagerTile },
                 { colorCorrectionTile }
         )
         // When adding/removing tiles, fix also [specMap]
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 2126dda..f5554c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -27,6 +29,7 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -34,6 +37,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.BootCompleteCache;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.appops.AppOpItem;
@@ -43,6 +47,7 @@
 import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DeviceConfigProxyFake;
+import com.android.systemui.util.settings.SecureSettings;
 
 import com.google.common.collect.ImmutableList;
 
@@ -60,9 +65,11 @@
     private LocationControllerImpl mLocationController;
     private TestableLooper mTestableLooper;
     private DeviceConfigProxy mDeviceConfigProxy;
+    private UiEventLoggerFake mUiEventLogger;
 
     @Mock private AppOpsController mAppOpsController;
     @Mock private UserTracker mUserTracker;
+    @Mock private SecureSettings mSecureSettings;
 
     @Before
     public void setup() {
@@ -72,6 +79,7 @@
         when(mUserTracker.getUserProfiles())
                 .thenReturn(ImmutableList.of(new UserInfo(0, "name", 0)));
         mDeviceConfigProxy = new DeviceConfigProxyFake();
+        mUiEventLogger = new UiEventLoggerFake();
 
         mTestableLooper = TestableLooper.get(this);
         mLocationController = new LocationControllerImpl(mContext,
@@ -82,7 +90,9 @@
                 mock(BroadcastDispatcher.class),
                 mock(BootCompleteCache.class),
                 mUserTracker,
-                mContext.getPackageManager());
+                mContext.getPackageManager(),
+                mUiEventLogger,
+                mSecureSettings);
 
         mTestableLooper.processAllMessages();
     }
@@ -160,6 +170,10 @@
         mTestableLooper.processAllMessages();
 
         verify(callback, times(1)).onLocationActiveChanged(anyBoolean());
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                LocationControllerImpl.LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER
+                        .getId());
     }
 
     @Test
@@ -194,7 +208,7 @@
     }
 
     @Test
-    public void testCallbackNotified_additionalOps_shouldShowSystem() {
+    public void testCallbackNotified_additionalOps_shouldNotShowSystem() {
         LocationChangeCallback callback = mock(LocationChangeCallback.class);
         mLocationController.addCallback(callback);
         mDeviceConfigProxy.setProperty(
@@ -219,7 +233,9 @@
 
 
     @Test
-    public void testCallbackNotified_additionalOps_shouldNotShowSystem() {
+    public void testCallbackNotified_additionalOps_shouldShowSystem() {
+        when(mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0))
+                .thenReturn(1);
         LocationChangeCallback callback = mock(LocationChangeCallback.class);
         mLocationController.addCallback(callback);
         mDeviceConfigProxy.setProperty(
@@ -251,6 +267,66 @@
         mTestableLooper.processAllMessages();
 
         verify(callback, times(1)).onLocationActiveChanged(false);
+
+        when(mSecureSettings.getInt(Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0))
+                .thenReturn(0);
+        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+                "com.google.android.gms", true);
+
+        mTestableLooper.processAllMessages();
+
+        // onLocationActive(true) was not called again because the setting is disabled.
+        verify(callback, times(1)).onLocationActiveChanged(true);
+    }
+
+    @Test
+    public void testCallbackNotified_verifyMetrics() {
+        LocationChangeCallback callback = mock(LocationChangeCallback.class);
+        mLocationController.addCallback(callback);
+        mDeviceConfigProxy.setProperty(
+                DeviceConfig.NAMESPACE_PRIVACY,
+                SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
+                "true",
+                true);
+        mTestableLooper.processAllMessages();
+
+        when(mAppOpsController.getActiveAppOps())
+                .thenReturn(ImmutableList.of(
+                        new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0, "com.google.android.gms",
+                                System.currentTimeMillis()),
+                        new AppOpItem(AppOpsManager.OP_COARSE_LOCATION, 0,
+                                "com.google.android.googlequicksearchbox",
+                                System.currentTimeMillis()),
+                        new AppOpItem(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+                                "com.google.android.apps.maps",
+                                System.currentTimeMillis())));
+        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+                "com.google.android.gms", true);
+
+        mTestableLooper.processAllMessages();
+
+        verify(callback, times(1)).onLocationActiveChanged(true);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(3);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                LocationControllerImpl.LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER
+                        .getId());
+        // Even though the system access wasn't shown due to the device settings, ensure it was
+        // still logged.
+        assertThat(mUiEventLogger.eventId(1)).isEqualTo(
+                LocationControllerImpl.LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP
+                        .getId());
+        assertThat(mUiEventLogger.eventId(2)).isEqualTo(
+                LocationControllerImpl.LocationIndicatorEvent.LOCATION_INDICATOR_NON_SYSTEM_APP
+                        .getId());
+        mUiEventLogger.getLogs().clear();
+
+        when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
+        mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+                "com.google.android.gms", false);
+        mTestableLooper.processAllMessages();
+
+        verify(callback, times(1)).onLocationActiveChanged(false);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(0);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 2f2e536..6593823 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -32,6 +32,7 @@
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.wm.shell.ShellCommandHandler;
 import com.android.wm.shell.common.ShellExecutor;
@@ -79,6 +80,7 @@
     @Mock ProtoTracer mProtoTracer;
     @Mock ShellCommandHandler mShellCommandHandler;
     @Mock CompatUI mCompatUI;
+    @Mock UserInfoController mUserInfoController;
     @Mock ShellExecutor mSysUiMainExecutor;
     @Mock DragAndDrop mDragAndDrop;
 
@@ -92,7 +94,7 @@
                 Optional.of(mDragAndDrop),
                 mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
                 mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
-                mWakefulnessLifecycle, mSysUiMainExecutor);
+                mWakefulnessLifecycle, mUserInfoController, mSysUiMainExecutor);
     }
 
     @Test
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 5c8fb2e..95b9e58 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -45,10 +45,12 @@
 import android.hardware.input.VirtualTouchEvent;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -59,6 +61,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Map;
 import java.util.Set;
 
 
@@ -78,6 +81,7 @@
     private final OnDeviceCloseListener mListener;
     private final IBinder mAppToken;
     private final VirtualDeviceParams mParams;
+    private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
     private final IVirtualDeviceActivityListener mActivityListener;
 
     private ActivityListener createListenerAdapter(int displayId) {
@@ -206,6 +210,16 @@
 
     @Override // Binder call
     public void close() {
+        synchronized (mVirtualDeviceLock) {
+            if (!mPerDisplayWakelocks.isEmpty()) {
+                mPerDisplayWakelocks.forEach((displayId, wakeLock) -> {
+                    Slog.w(TAG, "VirtualDisplay " + displayId + " owned by UID " + mOwnerUid
+                            + " was not properly released");
+                    wakeLock.release();
+                });
+                mPerDisplayWakelocks.clear();
+            }
+        }
         mListener.onClose(mAssociationInfo.getId());
         mAppToken.unlinkToDeath(this, 0);
         mInputController.close();
@@ -383,22 +397,48 @@
     }
 
     DisplayWindowPolicyController onVirtualDisplayCreatedLocked(int displayId) {
-        if (mVirtualDisplayIds.contains(displayId)) {
-            throw new IllegalStateException(
-                    "Virtual device already have a virtual display with ID " + displayId);
+        synchronized (mVirtualDeviceLock) {
+            if (mVirtualDisplayIds.contains(displayId)) {
+                throw new IllegalStateException(
+                        "Virtual device already have a virtual display with ID " + displayId);
+            }
+            mVirtualDisplayIds.add(displayId);
+
+            // Since we're being called in the middle of the display being created, we post a
+            // task to grab the wakelock instead of doing it synchronously here, to avoid
+            // reentrancy  problems.
+            mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
+
+            LocalServices.getService(
+                    InputManagerInternal.class).setDisplayEligibilityForPointerCapture(displayId,
+                    false);
+            final GenericWindowPolicyController dwpc =
+                    new GenericWindowPolicyController(FLAG_SECURE,
+                            SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+                            getAllowedUserHandles(),
+                            mParams.getAllowedActivities(),
+                            mParams.getBlockedActivities(),
+                            createListenerAdapter(displayId));
+            mWindowPolicyControllers.put(displayId, dwpc);
+            return dwpc;
         }
-        mVirtualDisplayIds.add(displayId);
-        LocalServices.getService(InputManagerInternal.class).setDisplayEligibilityForPointerCapture(
-                displayId, false);
-        final GenericWindowPolicyController dwpc =
-                new GenericWindowPolicyController(FLAG_SECURE,
-                        SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
-                        getAllowedUserHandles(),
-                        mParams.getAllowedActivities(),
-                        mParams.getBlockedActivities(),
-                        createListenerAdapter(displayId));
-        mWindowPolicyControllers.put(displayId, dwpc);
-        return dwpc;
+    }
+
+    void addWakeLockForDisplay(int displayId) {
+        synchronized (mVirtualDeviceLock) {
+            if (!mVirtualDisplayIds.contains(displayId)
+                    || mPerDisplayWakelocks.containsKey(displayId)) {
+                Slog.e(TAG, "Not creating wakelock for displayId " + displayId);
+                return;
+            }
+            PowerManager powerManager = mContext.getSystemService(PowerManager.class);
+            PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+                    PowerManager.SCREEN_BRIGHT_WAKE_LOCK
+                            | PowerManager.ACQUIRE_CAUSES_WAKEUP,
+                    TAG + ":" + displayId, displayId);
+            wakeLock.acquire();
+            mPerDisplayWakelocks.put(displayId, wakeLock);
+        }
     }
 
     private ArraySet<UserHandle> getAllowedUserHandles() {
@@ -420,14 +460,22 @@
     }
 
     void onVirtualDisplayRemovedLocked(int displayId) {
-        if (!mVirtualDisplayIds.contains(displayId)) {
-            throw new IllegalStateException(
-                    "Virtual device doesn't have a virtual display with ID " + displayId);
+        synchronized (mVirtualDeviceLock) {
+            if (!mVirtualDisplayIds.contains(displayId)) {
+                throw new IllegalStateException(
+                        "Virtual device doesn't have a virtual display with ID " + displayId);
+            }
+            PowerManager.WakeLock wakeLock = mPerDisplayWakelocks.get(displayId);
+            if (wakeLock != null) {
+                wakeLock.release();
+                mPerDisplayWakelocks.remove(displayId);
+            }
+            mVirtualDisplayIds.remove(displayId);
+            LocalServices.getService(
+                    InputManagerInternal.class).setDisplayEligibilityForPointerCapture(
+                    displayId, true);
+            mWindowPolicyControllers.remove(displayId);
         }
-        mVirtualDisplayIds.remove(displayId);
-        LocalServices.getService(InputManagerInternal.class).setDisplayEligibilityForPointerCapture(
-                displayId, true);
-        mWindowPolicyControllers.remove(displayId);
     }
 
     int getOwnerUid() {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 5d48d78..2f8dea7 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -323,13 +323,20 @@
         if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.chargerAcOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0
+                && mHealthInfo.chargerAcOnline) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.chargerUsbOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0
+                && mHealthInfo.chargerUsbOnline) {
             return true;
         }
-        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.chargerWirelessOnline) {
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0
+                && mHealthInfo.chargerWirelessOnline) {
+            return true;
+        }
+        if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_DOCK) != 0
+                && mHealthInfo.chargerDockOnline) {
             return true;
         }
         return false;
@@ -442,6 +449,8 @@
             return BatteryManager.BATTERY_PLUGGED_USB;
         } else if (healthInfo.chargerWirelessOnline) {
             return BatteryManager.BATTERY_PLUGGED_WIRELESS;
+        } else if (healthInfo.chargerDockOnline) {
+            return BatteryManager.BATTERY_PLUGGED_DOCK;
         } else {
             return BATTERY_PLUGGED_NONE;
         }
@@ -1118,6 +1127,8 @@
                 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_USB;
             } else if (mHealthInfo.chargerWirelessOnline) {
                 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS;
+            } else if (mHealthInfo.chargerDockOnline) {
+                batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_DOCK;
             }
             proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
             proto.write(
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 9923274..ed545a6 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -227,6 +227,76 @@
     }
 
     /**
+     * Class representing the types of "onUser" events that we are being informed about as having
+     * finished.
+     *
+     * @hide
+     */
+    public static final class UserCompletedEventType {
+        /**
+         * Flag representing the {@link #onUserStarting} event.
+         * @hide
+         */
+        public static final int EVENT_TYPE_USER_STARTING = 1 << 0;
+        /**
+         * Flag representing the {@link #onUserUnlocked} event.
+         * @hide
+         */
+        public static final int EVENT_TYPE_USER_UNLOCKED = 1 << 1;
+        /**
+         * Flag representing the {@link #onUserSwitching} event.
+         * @hide
+         */
+        public static final int EVENT_TYPE_USER_SWITCHING = 1 << 2;
+
+        /**
+         * @hide
+         */
+        @IntDef(flag = true, prefix = "EVENT_TYPE_USER_", value = {
+                EVENT_TYPE_USER_STARTING,
+                EVENT_TYPE_USER_UNLOCKED,
+                EVENT_TYPE_USER_SWITCHING
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface EventTypesFlag {
+        }
+
+        private @EventTypesFlag int mEventType;
+
+        /** @hide */
+        UserCompletedEventType(@EventTypesFlag int eventType) {
+            mEventType = eventType;
+        }
+
+        /** Returns whether one of the events is {@link #onUserStarting}. */
+        public boolean includesOnUserStarting() {
+            return (mEventType & EVENT_TYPE_USER_STARTING) != 0;
+        }
+
+        /** Returns whether one of the events is {@link #onUserUnlocked}. */
+        public boolean includesOnUserUnlocked() {
+            return (mEventType & EVENT_TYPE_USER_UNLOCKED) != 0;
+        }
+
+        /** Returns whether one of the events is {@link #onUserSwitching}. */
+        public boolean includesOnUserSwitching() {
+            return (mEventType & EVENT_TYPE_USER_SWITCHING) != 0;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("{");
+            // List each in reverse order (to line up with binary better).
+            if (includesOnUserSwitching()) sb.append("|Switching");
+            if (includesOnUserUnlocked()) sb.append("|Unlocked");
+            if (includesOnUserStarting()) sb.append("|Starting");
+            if (sb.length() > 1) sb.append("|");
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+
+    /**
      * Initializes the system service.
      * <p>
      * Subclasses must define a single argument constructor that accepts the context
@@ -407,6 +477,33 @@
     }
 
     /**
+     * Called some time <i>after</i> an onUser... event has completed, for the events delineated in
+     * {@link UserCompletedEventType}. May include more than one event.
+     *
+     * <p>
+     * This can be useful for processing tasks that must run after such an event but are non-urgent.
+     *
+     * There are no strict guarantees about how long after the event this will be called, only that
+     * it will be called if applicable. There is no guarantee about the order in which each service
+     * is informed, and these calls may be made in parallel using a thread pool.
+     *
+     * <p>Note that if the event is no longer applicable (for example, we switched to user 10, but
+     * before this method was called, we switched to user 11), the event will not be included in the
+     * {@code eventType} (i.e. user 10 won't mention the switch - even though it happened, it is no
+     * longer applicable).
+     *
+     * <p>This method is only called when the service {@link #isUserSupported(TargetUser) supports}
+     * this user.
+     *
+     * @param user target user completing the event (e.g. user being switched to)
+     * @param eventType the types of onUser event applicable (e.g. user starting and being unlocked)
+     *
+     * @hide
+     */
+    public void onUserCompletedEvent(@NonNull TargetUser user, UserCompletedEventType eventType) {
+    }
+
+    /**
      * Publish the service so it is accessible to other services and apps.
      *
      * @param name the name of the new service
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index e7f4de2..0bc3fcc 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -36,6 +36,7 @@
 import com.android.internal.os.SystemServerClassLoaderFactory;
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService.TargetUser;
+import com.android.server.SystemService.UserCompletedEventType;
 import com.android.server.am.EventLogTags;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
@@ -73,6 +74,7 @@
     private static final String USER_SWITCHING = "Switch"; // Logged as onSwitchUser
     private static final String USER_STOPPING = "Stop"; // Logged as onStopUser
     private static final String USER_STOPPED = "Cleanup"; // Logged as onCleanupUser
+    private static final String USER_COMPLETED_EVENT = "CompletedEvent"; // onCompletedEventUser
 
     // Whether to use multiple threads to run user lifecycle phases in parallel.
     private static boolean sUseLifecycleThreadPool = true;
@@ -404,6 +406,26 @@
         }
     }
 
+    /**
+     * Called some time <i>after</i> an onUser... event has completed, for the events delineated in
+     * {@link UserCompletedEventType}.
+     *
+     * @param eventFlags the events that completed, per {@link UserCompletedEventType}, or 0.
+     * @see SystemService#onUserCompletedEvent
+     */
+    public void onUserCompletedEvent(@UserIdInt int userId,
+            @UserCompletedEventType.EventTypesFlag int eventFlags) {
+        EventLog.writeEvent(EventLogTags.SSM_USER_COMPLETED_EVENT, userId, eventFlags);
+        if (eventFlags == 0) {
+            return;
+        }
+        onUser(TimingsTraceAndSlog.newAsyncLog(),
+                USER_COMPLETED_EVENT,
+                /* prevUser= */ null,
+                getTargetUser(userId),
+                new UserCompletedEventType(eventFlags));
+    }
+
     private void onUser(@NonNull String onWhat, @UserIdInt int userId) {
         onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, /* prevUser= */ null,
                 getTargetUser(userId));
@@ -411,19 +433,23 @@
 
     private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
             @Nullable TargetUser prevUser, @NonNull TargetUser curUser) {
+        onUser(t, onWhat, prevUser, curUser, /* completedEventType=*/ null);
+    }
+
+    private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
+            @Nullable TargetUser prevUser, @NonNull TargetUser curUser,
+            @Nullable UserCompletedEventType completedEventType) {
         final int curUserId = curUser.getUserIdentifier();
         // NOTE: do not change label below, or it might break performance tests that rely on it.
         t.traceBegin("ssm." + onWhat + "User-" + curUserId);
         Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId
                 + (prevUser != null ? " (from " + prevUser + ")" : ""));
-        final int serviceLen = mServices.size();
-        // Limit the lifecycle parallelization to all users other than the system user
-        // and only for the user start lifecycle phase for now.
-        final boolean useThreadPool = sUseLifecycleThreadPool
-                && curUserId != UserHandle.USER_SYSTEM
-                && onWhat.equals(USER_STARTING);
+
+        final boolean useThreadPool = useThreadPool(curUserId, onWhat);
         final ExecutorService threadPool =
                 useThreadPool ? Executors.newFixedThreadPool(mNumUserPoolThreads) : null;
+
+        final int serviceLen = mServices.size();
         for (int i = 0; i < serviceLen; i++) {
             final SystemService service = mServices.get(i);
             final String serviceName = service.getClass().getName();
@@ -446,8 +472,7 @@
                 }
                 continue;
             }
-            // Only submit this service to the thread pool if it's in the "other" category.
-            final boolean submitToThreadPool = useThreadPool && i >= sOtherServicesStartIndex;
+            final boolean submitToThreadPool = useThreadPool && useThreadPoolForService(onWhat, i);
             if (!submitToThreadPool) {
                 t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName);
             }
@@ -459,7 +484,7 @@
                         break;
                     case USER_STARTING:
                         if (submitToThreadPool) {
-                            threadPool.submit(getOnStartUserRunnable(t, service, curUser));
+                            threadPool.submit(getOnUserStartingRunnable(t, service, curUser));
                         } else {
                             service.onUserStarting(curUser);
                         }
@@ -476,6 +501,10 @@
                     case USER_STOPPED:
                         service.onUserStopped(curUser);
                         break;
+                    case USER_COMPLETED_EVENT:
+                        threadPool.submit(getOnUserCompletedEventRunnable(
+                                t, service, serviceName, curUser, completedEventType));
+                        break;
                     default:
                         throw new IllegalArgumentException(onWhat + " what?");
                 }
@@ -498,9 +527,11 @@
             } catch (InterruptedException e) {
                 Slog.wtf(TAG, "User lifecycle thread pool was interrupted while awaiting completion"
                         + " of " + onWhat + " of user " + curUser, e);
-                Slog.e(TAG, "Couldn't terminate, disabling thread pool. "
-                        + "Please capture a bug report.");
-                sUseLifecycleThreadPool = false;
+                if (!onWhat.equals(USER_COMPLETED_EVENT)) {
+                    Slog.e(TAG, "Couldn't terminate, disabling thread pool. "
+                            + "Please capture a bug report.");
+                    sUseLifecycleThreadPool = false;
+                }
             }
             if (!terminated) {
                 Slog.wtf(TAG, "User lifecycle thread pool was not terminated.");
@@ -509,7 +540,38 @@
         t.traceEnd(); // main entry
     }
 
-    private Runnable getOnStartUserRunnable(TimingsTraceAndSlog oldTrace, SystemService service,
+    /**
+     * Whether the given onWhat should use a thread pool.
+     * IMPORTANT: changing the logic to return true won't necessarily make it multi-threaded.
+     *            There needs to be a corresponding logic change in onUser() to actually submit
+     *            to a threadPool for the given onWhat.
+     */
+    private boolean useThreadPool(int userId, @NonNull String onWhat) {
+        switch (onWhat) {
+            case USER_STARTING:
+                // Limit the lifecycle parallelization to all users other than the system user
+                // and only for the user start lifecycle phase for now.
+                return sUseLifecycleThreadPool && userId != UserHandle.USER_SYSTEM;
+            case USER_COMPLETED_EVENT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private boolean useThreadPoolForService(@NonNull String onWhat, int serviceIndex) {
+        switch (onWhat) {
+            case USER_STARTING:
+                // Only submit this service to the thread pool if it's in the "other" category.
+                return serviceIndex >= sOtherServicesStartIndex;
+            case USER_COMPLETED_EVENT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private Runnable getOnUserStartingRunnable(TimingsTraceAndSlog oldTrace, SystemService service,
             TargetUser curUser) {
         return () -> {
             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace);
@@ -531,6 +593,22 @@
         };
     }
 
+    private Runnable getOnUserCompletedEventRunnable(TimingsTraceAndSlog oldTrace,
+            SystemService service, String serviceName, TargetUser curUser,
+            UserCompletedEventType eventType) {
+        return () -> {
+            final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace);
+            final int curUserId = curUser.getUserIdentifier();
+            t.traceBegin("ssm.on" + USER_COMPLETED_EVENT + "User-" + curUserId
+                    + "_" + eventType + "_" + serviceName);
+            long time = SystemClock.elapsedRealtime();
+            service.onUserCompletedEvent(curUser, eventType);
+            warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
+                    "on" + USER_COMPLETED_EVENT + "User-" + curUserId);
+            t.traceEnd();
+        };
+    }
+
     /** Sets the safe mode flag for services to query. */
     void setSafeMode(boolean safeMode) {
         mSafeMode = safeMode;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b1b4c44..f67e732 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2871,51 +2871,13 @@
         return mode == AppOpsManager.MODE_ALLOWED;
     }
 
-    /**
-     * Checks whether the calling package is trusted.
-     *
-     * The calling package is trusted if it's from system or the supposed package name matches the
-     * UID making the call.
-     *
-     * @throws SecurityException if the package name and UID don't match.
-     */
-    private void verifyCallingPackage(String callingPackage) {
-        final int callingUid = Binder.getCallingUid();
-        // The caller is System or Shell.
-        if (callingUid == SYSTEM_UID || isCallerShell()) {
-            return;
-        }
-
-        // Handle the special UIDs that don't have real package (audioserver, cameraserver, etc).
-        final String resolvedPackage = AppOpsManager.resolvePackageName(callingUid,
-                null /* packageName */);
-        if (resolvedPackage != null && resolvedPackage.equals(callingPackage)) {
-            return;
-        }
-
-        final int claimedUid = getPackageManagerInternal().getPackageUid(callingPackage,
-                0 /* flags */, UserHandle.getUserId(callingUid));
-        if (callingUid == claimedUid) {
-            return;
-        }
-
-        throw new SecurityException(
-                "Claimed calling package " + callingPackage + " does not match the calling UID "
-                        + Binder.getCallingUid());
-    }
-
-    private void enforceUsageStatsPermission(String callingPackage, String func) {
-        verifyCallingPackage(callingPackage);
-        // Since the protection level of PACKAGE_USAGE_STATS has 'appop', apps may grant this
-        // permission via that way. We need to check both app-ops and permission.
-        if (!hasUsageStatsPermission(callingPackage)) {
-            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, func);
-        }
-    }
-
     @Override
     public int getPackageProcessState(String packageName, String callingPackage) {
-        enforceUsageStatsPermission(callingPackage, "getPackageProcessState");
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "getPackageProcessState");
+        }
+
         final int[] procState = {PROCESS_STATE_NONEXISTENT};
         synchronized (mProcLock) {
             mProcessList.forEachLruProcessesLOSP(false, proc -> {
@@ -6976,7 +6938,11 @@
 
     @Override
     public int getUidProcessState(int uid, String callingPackage) {
-        enforceUsageStatsPermission(callingPackage, "getUidProcessState");
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "getUidProcessState");
+        }
+
         synchronized (mProcLock) {
             return mProcessList.getUidProcStateLOSP(uid);
         }
@@ -6984,7 +6950,11 @@
 
     @Override
     public @ProcessCapability int getUidProcessCapabilities(int uid, String callingPackage) {
-        enforceUsageStatsPermission(callingPackage, "getUidProcessCapabilities");
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "getUidProcessState");
+        }
+
         synchronized (mProcLock) {
             return mProcessList.getUidProcessCapabilityLOSP(uid);
         }
@@ -6993,7 +6963,10 @@
     @Override
     public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
             String callingPackage) {
-        enforceUsageStatsPermission(callingPackage, "registerUidObserver");
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "registerUidObserver");
+        }
         mUidObserverController.register(observer, which, cutpoint, callingPackage,
                 Binder.getCallingUid());
     }
@@ -7005,7 +6978,10 @@
 
     @Override
     public boolean isUidActive(int uid, String callingPackage) {
-        enforceUsageStatsPermission(callingPackage, "isUidActive");
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "isUidActive");
+        }
         synchronized (mProcLock) {
             if (isUidActiveLOSP(uid)) {
                 return true;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index bb939b7..ec6b782 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -28,6 +28,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
@@ -37,6 +38,7 @@
 import android.app.PendingIntent;
 import android.app.RemoteServiceException.CannotDeliverBroadcastException;
 import android.app.usage.UsageEvents.Event;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.IIntentReceiver;
@@ -69,6 +71,7 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -325,6 +328,7 @@
         mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
 
         // Tell the application to launch this receiver.
+        maybeReportBroadcastDispatchedEventLocked(r);
         r.intent.setComponent(r.curComponent);
 
         boolean started = false;
@@ -917,6 +921,7 @@
                 r.receiverTime = SystemClock.uptimeMillis();
                 maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                 maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
+                maybeReportBroadcastDispatchedEventLocked(r);
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                         new Intent(r.intent), r.resultCode, r.resultData,
                         r.resultExtras, r.ordered, r.initialSticky, r.userId);
@@ -1831,6 +1836,45 @@
         mPendingBroadcastRecvIndex = recIdx;
     }
 
+
+    @Nullable
+    private String getTargetPackage(BroadcastRecord r) {
+        if (r.intent == null) {
+            return null;
+        }
+        if (r.intent.getPackage() != null) {
+            return r.intent.getPackage();
+        } else if (r.intent.getComponent() != null) {
+            return r.intent.getComponent().getPackageName();
+        }
+        return null;
+    }
+
+    private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r) {
+        final String targetPackage = getTargetPackage(r);
+        // Ignore non-explicit broadcasts
+        if (targetPackage == null) {
+            return;
+        }
+        // TODO (206518114): Only allow apps with ACCESS_PACKAGE_USAGE_STATS to set
+        // getIdForResponseEvent.
+        if (r.options == null || r.options.getIdForResponseEvent() <= 0) {
+            return;
+        }
+        // TODO (206518114): Only report this event when the broadcast is dispatched while the app
+        // is in the background state.
+        getUsageStatsManagerInternal().reportBroadcastDispatched(
+                r.callingUid, targetPackage, UserHandle.of(r.userId),
+                r.options.getIdForResponseEvent(), SystemClock.elapsedRealtime());
+    }
+
+    @NonNull
+    private UsageStatsManagerInternal getUsageStatsManagerInternal() {
+        final UsageStatsManagerInternal usageStatsManagerInternal =
+                LocalServices.getService(UsageStatsManagerInternal.class);
+        return usageStatsManagerInternal;
+    }
+
     private boolean noteOpForManifestReceiver(int appOp, BroadcastRecord r, ResolveInfo info,
             ComponentName component) {
         if (ArrayUtils.isEmpty(info.activityInfo.attributionTags)) {
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 68f2e35..b250a0c 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -115,3 +115,4 @@
 30085 ssm_user_unlocked (userId|1|5)
 30086 ssm_user_stopping (userId|1|5)
 30087 ssm_user_stopped (userId|1|5)
+30088 ssm_user_completed_event (userId|1|5),(eventFlag|1|5)
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 252584c..e4c0846 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -109,6 +109,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.SystemService.UserCompletedEventType;
 import com.android.server.SystemServiceManager;
 import com.android.server.am.UserState.KeyEvictedCallback;
 import com.android.server.pm.UserManagerInternal;
@@ -166,6 +167,7 @@
     static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 110;
     static final int START_USER_SWITCH_FG_MSG = 120;
     static final int COMPLETE_USER_SWITCH_MSG = 130;
+    static final int USER_COMPLETED_EVENT_MSG = 140;
 
     // Message constant to clear {@link UserJourneySession} from {@link mUserIdToUserJourneyMap} if
     // the user journey, defined in the UserLifecycleJourneyReported atom for statsd, is not
@@ -184,6 +186,14 @@
     // when it never calls back.
     private static final int USER_SWITCH_CALLBACKS_TIMEOUT_MS = 5 * 1000;
 
+    /**
+     * Time after last scheduleOnUserCompletedEvent() call at which USER_COMPLETED_EVENT_MSG will be
+     * scheduled (although it may fire sooner instead).
+     * When it fires, {@link #reportOnUserCompletedEvent} will be processed.
+     */
+    // TODO(b/197344658): Increase to 10s or 15s once we have a switch-UX-is-done invocation too.
+    private static final int USER_COMPLETED_EVENT_DELAY_MS = 5 * 1000;
+
     // Used for statsd logging with UserLifecycleJourneyReported + UserLifecycleEventOccurred atoms
     private static final long INVALID_SESSION_ID = 0;
 
@@ -365,6 +375,13 @@
     private final SparseArray<UserJourneySession> mUserIdToUserJourneyMap = new SparseArray<>();
 
     /**
+     * Map of userId to {@link UserCompletedEventType} event flags, indicating which as-yet-
+     * unreported user-starting events have transpired for the given user.
+     */
+    @GuardedBy("mCompletedEventTypes")
+    private final SparseIntArray mCompletedEventTypes = new SparseIntArray();
+
+    /**
      * Sets on {@link #setInitialConfig(boolean, int, boolean)}, which is called by
      * {@code ActivityManager} when the system is started.
      *
@@ -2778,6 +2795,9 @@
 
                 mInjector.getSystemServiceManager().onUserStarting(
                         TimingsTraceAndSlog.newAsyncLog(), msg.arg1);
+                scheduleOnUserCompletedEvent(msg.arg1,
+                        UserCompletedEventType.EVENT_TYPE_USER_STARTING,
+                        USER_COMPLETED_EVENT_DELAY_MS);
 
                 logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_START_USER,
                         USER_LIFECYCLE_EVENT_STATE_FINISH);
@@ -2802,6 +2822,13 @@
                 break;
             case USER_UNLOCKED_MSG:
                 mInjector.getSystemServiceManager().onUserUnlocked(msg.arg1);
+                scheduleOnUserCompletedEvent(msg.arg1,
+                        UserCompletedEventType.EVENT_TYPE_USER_UNLOCKED,
+                        // If it's the foreground user, we wait longer to let it fully load.
+                        // Else, there's nothing specific to wait for, so we basically just proceed.
+                        // (No need to acquire lock to read mCurrentUserId since it is volatile.)
+                        // TODO: Find something to wait for in the case of a profile.
+                        mCurrentUserId == msg.arg1 ? USER_COMPLETED_EVENT_DELAY_MS : 1000);
                 logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_UNLOCKED_USER,
                         USER_LIFECYCLE_EVENT_STATE_FINISH);
                 clearSessionId(msg.arg1);
@@ -2815,6 +2842,12 @@
                         Integer.toString(msg.arg1), msg.arg1);
 
                 mInjector.getSystemServiceManager().onUserSwitching(msg.arg2, msg.arg1);
+                scheduleOnUserCompletedEvent(msg.arg1,
+                        UserCompletedEventType.EVENT_TYPE_USER_SWITCHING,
+                        USER_COMPLETED_EVENT_DELAY_MS);
+                break;
+            case USER_COMPLETED_EVENT_MSG:
+                reportOnUserCompletedEvent((Integer) msg.obj);
                 break;
             case FOREGROUND_PROFILE_CHANGED_MSG:
                 dispatchForegroundProfileChanged(msg.arg1);
@@ -2847,6 +2880,71 @@
     }
 
     /**
+     * Schedules {@link SystemServiceManager#onUserCompletedEvent()} with the given
+     * {@link UserCompletedEventType} event, which will be combined with any other events for that
+     * user already scheduled.
+     * If it isn't rescheduled first, it will fire after a delayMs delay.
+     *
+     * @param eventType event type flags from {@link UserCompletedEventType} to append to the
+     *                  schedule. Use 0 to schedule the ssm call without modifying the event types.
+     */
+    // TODO(b/197344658): Also call scheduleOnUserCompletedEvent(userId, 0, 0) after switch UX done.
+    @VisibleForTesting
+    void scheduleOnUserCompletedEvent(
+            int userId, @UserCompletedEventType.EventTypesFlag int eventType, int delayMs) {
+
+        if (eventType != 0) {
+            synchronized (mCompletedEventTypes) {
+                mCompletedEventTypes.put(userId, mCompletedEventTypes.get(userId, 0) | eventType);
+            }
+        }
+
+        final Object msgObj = userId;
+        mHandler.removeEqualMessages(USER_COMPLETED_EVENT_MSG, msgObj);
+        mHandler.sendMessageDelayed(
+                mHandler.obtainMessage(USER_COMPLETED_EVENT_MSG, msgObj),
+                delayMs);
+    }
+
+    /**
+     * Calls {@link SystemServiceManager#onUserCompletedEvent()} for the given user, sending all the
+     * {@link UserCompletedEventType} events that have been scheduled for it if they are still
+     * applicable.
+     *
+     * Called on the mHandler thread.
+     */
+    @VisibleForTesting
+    void reportOnUserCompletedEvent(Integer userId) {
+        mHandler.removeEqualMessages(USER_COMPLETED_EVENT_MSG, userId);
+
+        int eventTypes;
+        synchronized (mCompletedEventTypes) {
+            eventTypes = mCompletedEventTypes.get(userId, 0);
+            mCompletedEventTypes.delete(userId);
+        }
+
+        // Now, remove any eventTypes that are no longer true.
+        int eligibleEventTypes = 0;
+        synchronized (mLock) {
+            final UserState uss = mStartedUsers.get(userId);
+            if (uss != null && uss.state != UserState.STATE_SHUTDOWN) {
+                eligibleEventTypes |= UserCompletedEventType.EVENT_TYPE_USER_STARTING;
+            }
+            if (uss != null && uss.state == STATE_RUNNING_UNLOCKED) {
+                eligibleEventTypes |= UserCompletedEventType.EVENT_TYPE_USER_UNLOCKED;
+            }
+            if (userId == mCurrentUserId) {
+                eligibleEventTypes |= UserCompletedEventType.EVENT_TYPE_USER_SWITCHING;
+            }
+        }
+        Slogf.i(TAG, "reportOnUserCompletedEvent(%d): stored=%s, eligible=%s", userId,
+                Integer.toBinaryString(eventTypes), Integer.toBinaryString(eligibleEventTypes));
+        eventTypes &= eligibleEventTypes;
+
+        mInjector.systemServiceManagerOnUserCompletedEvent(userId, eventTypes);
+    }
+
+    /**
      * statsd helper method for logging the start of a user journey via a UserLifecycleEventOccurred
      * atom given the originating and targeting users for the journey.
      */
@@ -3086,7 +3184,11 @@
         }
 
         void systemServiceManagerOnUserStopped(@UserIdInt int userId) {
-            mService.mSystemServiceManager.onUserStopped(userId);
+            getSystemServiceManager().onUserStopped(userId);
+        }
+
+        void systemServiceManagerOnUserCompletedEvent(@UserIdInt int userId, int eventTypes) {
+            getSystemServiceManager().onUserCompletedEvent(userId, eventTypes);
         }
 
         protected UserManagerService getUserManager() {
@@ -3113,7 +3215,7 @@
         }
 
         boolean isRuntimeRestarted() {
-            return mService.mSystemServiceManager.isRuntimeRestarted();
+            return getSystemServiceManager().isRuntimeRestarted();
         }
 
         SystemServiceManager getSystemServiceManager() {
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
index b4c43f6..73278e4 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.app;
 
 import android.annotation.NonNull;
+import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
@@ -36,17 +37,19 @@
     private final Context mContext;
 
     GameServiceProviderInstanceFactoryImpl(@NonNull Context context) {
-        this.mContext = context;
+        mContext = context;
     }
 
     @NonNull
     @Override
-    public GameServiceProviderInstance create(@NonNull
-            GameServiceProviderConfiguration gameServiceProviderConfiguration) {
+    public GameServiceProviderInstance create(
+            @NonNull GameServiceProviderConfiguration gameServiceProviderConfiguration) {
         return new GameServiceProviderInstanceImpl(
                 gameServiceProviderConfiguration.getUserHandle(),
                 BackgroundThread.getExecutor(),
+                mContext,
                 new GameClassifierImpl(mContext.getPackageManager()),
+                ActivityManager.getService(),
                 ActivityTaskManager.getService(),
                 (WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
                 LocalServices.getService(WindowManagerInternal.class),
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 43c9839..8578de7 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -16,13 +16,18 @@
 
 package com.android.server.app;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
+import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.app.TaskStackListener;
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -110,12 +115,23 @@
                                 gameScreenshotResultFuture);
                     });
                 }
+
+                @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+                public void restartGame(int taskId) {
+                    mContext.enforceCallingPermission(Manifest.permission.FORCE_STOP_PACKAGES,
+                            "restartGame()");
+                    mBackgroundExecutor.execute(() -> {
+                        GameServiceProviderInstanceImpl.this.restartGame(taskId);
+                    });
+                }
             };
 
     private final Object mLock = new Object();
     private final UserHandle mUserHandle;
     private final Executor mBackgroundExecutor;
+    private final Context mContext;
     private final GameClassifier mGameClassifier;
+    private final IActivityManager mActivityManager;
     private final IActivityTaskManager mActivityTaskManager;
     private final WindowManagerService mWindowManagerService;
     private final WindowManagerInternal mWindowManagerInternal;
@@ -131,7 +147,9 @@
     GameServiceProviderInstanceImpl(
             @NonNull UserHandle userHandle,
             @NonNull Executor backgroundExecutor,
+            @NonNull Context context,
             @NonNull GameClassifier gameClassifier,
+            @NonNull IActivityManager activityManager,
             @NonNull IActivityTaskManager activityTaskManager,
             @NonNull WindowManagerService windowManagerService,
             @NonNull WindowManagerInternal windowManagerInternal,
@@ -139,7 +157,9 @@
             @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector) {
         mUserHandle = userHandle;
         mBackgroundExecutor = backgroundExecutor;
+        mContext = context;
         mGameClassifier = gameClassifier;
+        mActivityManager = activityManager;
         mActivityTaskManager = activityTaskManager;
         mWindowManagerService = windowManagerService;
         mWindowManagerInternal = windowManagerInternal;
@@ -310,6 +330,7 @@
                     + ") is not awaiting game session request. Ignoring.");
             return;
         }
+        mGameSessions.put(taskId, existingGameSessionRecord.withGameSessionRequested());
 
         GameSessionViewHostConfiguration gameSessionViewHostConfiguration =
                 createViewHostConfigurationForTask(taskId);
@@ -532,4 +553,27 @@
             }
         });
     }
+
+    private void restartGame(int taskId) {
+        String packageName;
+
+        synchronized (mLock) {
+            boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
+            if (!isTaskAssociatedWithGameSession) {
+                return;
+            }
+
+            packageName = mGameSessions.get(taskId).getComponentName().getPackageName();
+        }
+
+        try {
+            mActivityManager.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+
+        Intent launchIntent =
+                mContext.getPackageManager().getLaunchIntentForPackage(packageName);
+        mContext.startActivity(launchIntent);
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index f5a529b..8a62c34 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1376,9 +1376,6 @@
             case AudioSystem.DEVICE_OUT_USB_HEADSET:
                 connType = AudioRoutesInfo.MAIN_USB;
                 break;
-            case AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET:
-                connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
-                break;
         }
 
         synchronized (mCurAudioRoutes) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 6ec9836..42fca9b 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -371,7 +371,7 @@
      * @return false if SCO isn't connected
      */
     /*package*/ synchronized boolean isBluetoothScoOn() {
-        if (mBluetoothHeadset == null) {
+        if (mBluetoothHeadset == null || mBluetoothHeadsetDevice == null) {
             return false;
         }
         return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
@@ -505,7 +505,7 @@
         // Discard timeout message
         mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
         mBluetoothHeadset = headset;
-        setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
+        setBtScoActiveDevice(headset != null ? headset.getActiveDevice() : null);
         // Refresh SCO audio state
         checkScoAudioState();
         if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
@@ -513,7 +513,7 @@
             return;
         }
         boolean status = false;
-        if (mBluetoothHeadsetDevice != null) {
+        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
             switch (mScoAudioState) {
                 case SCO_STATE_ACTIVATE_REQ:
                     status = connectBluetoothScoAudioHelper(
@@ -552,6 +552,9 @@
     }
 
     private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
+        if (btDevice == null) {
+            return new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
+        }
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
diff --git a/services/core/java/com/android/server/clipboard/OWNERS b/services/core/java/com/android/server/clipboard/OWNERS
index 5449df9..0d5dbf9 100644
--- a/services/core/java/com/android/server/clipboard/OWNERS
+++ b/services/core/java/com/android/server/clipboard/OWNERS
@@ -1 +1,3 @@
 per-file EmulatorClipboardMonitor.java = bohu@google.com,lfy@google.com,rkir@google.com
+
+olilan@google.com
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 240168b..a1d722b 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -32,6 +32,7 @@
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.internal.util.Preconditions;
 import com.android.server.display.utils.Plog;
+import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -69,7 +70,7 @@
     @Nullable
     public static BrightnessMappingStrategy create(Resources resources,
             DisplayDeviceConfig displayDeviceConfig) {
-        return create(resources, displayDeviceConfig, /* isForIdleMode= */ false);
+        return create(resources, displayDeviceConfig, /* isForIdleMode= */ false, null);
     }
 
     /**
@@ -80,8 +81,10 @@
      */
     @Nullable
     public static BrightnessMappingStrategy createForIdleMode(Resources resources,
-            DisplayDeviceConfig displayDeviceConfig) {
-        return create(resources, displayDeviceConfig, /* isForIdleMode= */ true);
+            DisplayDeviceConfig displayDeviceConfig, DisplayWhiteBalanceController
+            displayWhiteBalanceController) {
+        return create(resources, displayDeviceConfig, /* isForIdleMode= */ true,
+                displayWhiteBalanceController);
     }
 
     /**
@@ -96,7 +99,8 @@
      */
     @Nullable
     private static BrightnessMappingStrategy create(Resources resources,
-            DisplayDeviceConfig displayDeviceConfig, boolean isForIdleMode) {
+            DisplayDeviceConfig displayDeviceConfig, boolean isForIdleMode,
+            DisplayWhiteBalanceController displayWhiteBalanceController) {
 
         // Display independent, mode dependent values
         float[] brightnessLevelsNits;
@@ -135,7 +139,7 @@
             builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
             builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
             return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange,
-                    autoBrightnessAdjustmentMaxGamma, isForIdleMode);
+                    autoBrightnessAdjustmentMaxGamma, isForIdleMode, displayWhiteBalanceController);
         } else if (isValidMapping(luxLevels, brightnessLevelsBacklight) && !isForIdleMode) {
             return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
                     autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout);
@@ -770,9 +774,11 @@
         private float mUserLux;
         private float mUserBrightness;
         private final boolean mIsForIdleMode;
+        private final DisplayWhiteBalanceController mDisplayWhiteBalanceController;
 
         public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
-                float[] brightness, float maxGamma, boolean isForIdleMode) {
+                float[] brightness, float maxGamma, boolean isForIdleMode,
+                DisplayWhiteBalanceController displayWhiteBalanceController) {
 
             Preconditions.checkArgument(nits.length != 0 && brightness.length != 0,
                     "Nits and brightness arrays must not be empty!");
@@ -789,6 +795,7 @@
             mAutoBrightnessAdjustment = 0;
             mUserLux = -1;
             mUserBrightness = -1;
+            mDisplayWhiteBalanceController = displayWhiteBalanceController;
 
             mNits = nits;
             mBrightness = brightness;
@@ -836,6 +843,12 @@
         public float getBrightness(float lux, String packageName,
                 @ApplicationInfo.Category int category) {
             float nits = mBrightnessSpline.interpolate(lux);
+
+            // Adjust nits to compensate for display white balance colour strength.
+            if (mDisplayWhiteBalanceController != null && isForIdleMode()) {
+                nits = mDisplayWhiteBalanceController.calculateAdjustedBrightnessNits(nits);
+            }
+
             float brightness = mNitsToBrightnessSpline.interpolate(nits);
             // Correct the brightness according to the current application and its category, but
             // only if no user data point is set (as this will override the user setting).
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 3feffc6..7ad4979 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1318,7 +1318,9 @@
 
         if (callingUid != Process.SYSTEM_UID
                 && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
-            if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
+            // The virtualDevice instance has been validated above using isValidVirtualDevice
+            if (virtualDevice == null
+                    && !checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) {
                 throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to "
                         + "create a virtual display which is not in the default DisplayGroup.");
             }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 31c496ed..ec4b91a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -50,6 +50,8 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.MathUtils;
+import android.util.MutableFloat;
+import android.util.MutableInt;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -895,7 +897,7 @@
                 mDisplayDeviceConfig);
         if (isIdleScreenBrightnessEnabled) {
             mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources,
-                    mDisplayDeviceConfig);
+                    mDisplayDeviceConfig, mDisplayWhiteBalanceController);
         }
 
         if (mInteractiveModeBrightnessMapper != null) {
@@ -1390,6 +1392,7 @@
 
         // Animate the screen brightness when the screen is on or dozing.
         // Skip the animation when the screen is off or suspended or transition to/from VR.
+        boolean brightnessAdjusted = false;
         if (!mPendingScreenOff) {
             if (mSkipScreenOnBrightnessRamp) {
                 if (state == Display.STATE_ON) {
@@ -1482,15 +1485,19 @@
                     // slider event so notify as if the system changed the brightness.
                     userInitiatedChange = false;
                 }
-                notifyBrightnessChanged(brightnessState, userInitiatedChange,
+                notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange,
                         hadUserBrightnessPoint);
             }
 
             // We save the brightness info *after* the brightness setting has been changed and
             // adjustments made so that the brightness info reflects the latest value.
-            saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
+            brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
         } else {
-            saveBrightnessInfo(getScreenBrightnessSetting());
+            brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting());
+        }
+
+        if (brightnessAdjusted) {
+            postBrightnessChangeRunnable();
         }
 
         // Log any changes to what is currently driving the brightness setting.
@@ -1606,31 +1613,50 @@
     public BrightnessInfo getBrightnessInfo() {
         synchronized (mCachedBrightnessInfo) {
             return new BrightnessInfo(
-                    mCachedBrightnessInfo.brightness,
-                    mCachedBrightnessInfo.adjustedBrightness,
-                    mCachedBrightnessInfo.brightnessMin,
-                    mCachedBrightnessInfo.brightnessMax,
-                    mCachedBrightnessInfo.hbmMode,
-                    mCachedBrightnessInfo.highBrightnessTransitionPoint);
+                    mCachedBrightnessInfo.brightness.value,
+                    mCachedBrightnessInfo.adjustedBrightness.value,
+                    mCachedBrightnessInfo.brightnessMin.value,
+                    mCachedBrightnessInfo.brightnessMax.value,
+                    mCachedBrightnessInfo.hbmMode.value,
+                    mCachedBrightnessInfo.hbmTransitionPoint.value);
         }
     }
 
-    private void saveBrightnessInfo(float brightness) {
-        saveBrightnessInfo(brightness, brightness);
+    private boolean saveBrightnessInfo(float brightness) {
+        return saveBrightnessInfo(brightness, brightness);
     }
 
-    private void saveBrightnessInfo(float brightness, float adjustedBrightness) {
+    private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
         synchronized (mCachedBrightnessInfo) {
-            mCachedBrightnessInfo.brightness = brightness;
-            mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness;
-            mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin();
-            mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax();
-            mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode();
-            mCachedBrightnessInfo.highBrightnessTransitionPoint =
-                mHbmController.getTransitionPoint();
+            boolean changed = false;
+
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightness,
+                        brightness);
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.adjustedBrightness,
+                        adjustedBrightness);
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin,
+                        mHbmController.getCurrentBrightnessMin());
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax,
+                        mHbmController.getCurrentBrightnessMax());
+            changed |=
+                mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
+                        mHbmController.getHighBrightnessMode());
+            changed |=
+                mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint,
+                        mHbmController.getTransitionPoint());
+
+            return changed;
         }
     }
 
+    void postBrightnessChangeRunnable() {
+        mHandler.post(mOnBrightnessChangeRunnable);
+    }
+
     private HighBrightnessModeController createHbmControllerLocked() {
         final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
         final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
@@ -1645,7 +1671,7 @@
                 displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
                 () -> {
                     sendUpdatePowerStateLocked();
-                    mHandler.post(mOnBrightnessChangeRunnable);
+                    postBrightnessChangeRunnable();
                     // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
                     if (mAutomaticBrightnessController != null) {
                         mAutomaticBrightnessController.update();
@@ -2147,7 +2173,7 @@
     private void setCurrentScreenBrightness(float brightnessValue) {
         if (brightnessValue != mCurrentScreenBrightnessSetting) {
             mCurrentScreenBrightnessSetting = brightnessValue;
-            mHandler.post(mOnBrightnessChangeRunnable);
+            postBrightnessChangeRunnable();
         }
     }
 
@@ -2199,7 +2225,7 @@
         return true;
     }
 
-    private void notifyBrightnessChanged(float brightness, boolean userInitiated,
+    private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated,
             boolean hadUserDataPoint) {
         final float brightnessInNits = convertToNits(brightness);
         if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f
@@ -2309,16 +2335,17 @@
         pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
         pw.println("  mColorFadeEnabled=" + mColorFadeEnabled);
         synchronized (mCachedBrightnessInfo) {
-            pw.println("  mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness);
+            pw.println("  mCachedBrightnessInfo.brightness=" +
+                    mCachedBrightnessInfo.brightness.value);
             pw.println("  mCachedBrightnessInfo.adjustedBrightness=" +
-                    mCachedBrightnessInfo.adjustedBrightness);
+                    mCachedBrightnessInfo.adjustedBrightness.value);
             pw.println("  mCachedBrightnessInfo.brightnessMin=" +
-                    mCachedBrightnessInfo.brightnessMin);
+                    mCachedBrightnessInfo.brightnessMin.value);
             pw.println("  mCachedBrightnessInfo.brightnessMax=" +
-                    mCachedBrightnessInfo.brightnessMax);
-            pw.println("  mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode);
-            pw.println("  mCachedBrightnessInfo.highBrightnessTransitionPoint=" +
-                    mCachedBrightnessInfo.highBrightnessTransitionPoint);
+                    mCachedBrightnessInfo.brightnessMax.value);
+            pw.println("  mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value);
+            pw.println("  mCachedBrightnessInfo.hbmTransitionPoint=" +
+                    mCachedBrightnessInfo.hbmTransitionPoint.value);
         }
         pw.println("  mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
         pw.println("  mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
@@ -2476,7 +2503,10 @@
     private void reportStats(float brightness) {
         float hbmTransitionPoint = PowerManager.BRIGHTNESS_MAX;
         synchronized(mCachedBrightnessInfo) {
-            hbmTransitionPoint = mCachedBrightnessInfo.highBrightnessTransitionPoint;
+            if (mCachedBrightnessInfo.hbmTransitionPoint == null) {
+                return;
+            }
+            hbmTransitionPoint = mCachedBrightnessInfo.hbmTransitionPoint.value;
         }
 
         final boolean aboveTransition = brightness > hbmTransitionPoint;
@@ -2773,11 +2803,31 @@
     }
 
     static class CachedBrightnessInfo {
-        public float brightness;
-        public float adjustedBrightness;
-        public float brightnessMin;
-        public float brightnessMax;
-        public int hbmMode;
-        public float highBrightnessTransitionPoint;
+        public MutableFloat brightness = new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableFloat adjustedBrightness =
+            new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableFloat brightnessMin =
+            new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableFloat brightnessMax =
+            new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        public MutableInt hbmMode = new MutableInt(BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
+        public MutableFloat hbmTransitionPoint =
+            new MutableFloat(HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID);
+
+        public boolean checkAndSetFloat(MutableFloat mf, float f) {
+            if (mf.value != f) {
+                mf.value = f;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean checkAndSetInt(MutableInt mi, int i) {
+            if (mi.value != i) {
+                mi.value = i;
+                return true;
+            }
+            return false;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index f9a1368..8035526 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -1453,7 +1453,7 @@
     /**
      * Local service that allows color transforms to be enabled from other system services.
      */
-    public final class ColorDisplayServiceInternal {
+    public class ColorDisplayServiceInternal {
 
         /**
          * Set the current CCT value for the display white balance transform, and if the transform
@@ -1472,6 +1472,11 @@
             return false;
         }
 
+        /** Get the luminance of the current chromatic adaptation matrix. */
+        public float getDisplayWhiteBalanceLuminance() {
+            return mDisplayWhiteBalanceTintController.getLuminance();
+        }
+
         /**
          * Reset the CCT value for the display white balance transform to its default value.
          */
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index bdbaaa8..936149c 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -251,6 +251,18 @@
         }
     }
 
+    public float getLuminance() {
+        synchronized (mLock) {
+            if (mChromaticAdaptationMatrix != null && mChromaticAdaptationMatrix.length == 9) {
+                // Compute only the luminance (y) value of the xyz * [1 1 1] transform.
+                return 1 / (mChromaticAdaptationMatrix[1] + mChromaticAdaptationMatrix[4]
+                        + mChromaticAdaptationMatrix[7]);
+            } else {
+                return -1;
+            }
+        }
+    }
+
     private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
         return new ColorSpace.Rgb(
                 "Display Color Space",
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index d64fcbc..151ec81 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -21,7 +21,6 @@
 import android.util.Spline;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
 import com.android.server.display.utils.AmbientFilter;
@@ -456,6 +455,22 @@
     }
 
     /**
+     * Calculate the adjusted brightness, in nits, due to the DWB color adaptation
+     *
+     * @param requestedBrightnessNits brightness the framework requires to be output
+     * @return the adjusted brightness the framework needs to output to counter the drop in
+     *         brightness due to DWB, or the requestedBrightnessNits if an adjustment cannot be made
+     */
+    public float calculateAdjustedBrightnessNits(float requestedBrightnessNits) {
+        float luminance = mColorDisplayServiceInternal.getDisplayWhiteBalanceLuminance();
+        if (luminance == -1) {
+            return requestedBrightnessNits;
+        }
+        float effectiveBrightness = requestedBrightnessNits * luminance;
+        return (requestedBrightnessNits - effectiveBrightness) + requestedBrightnessNits;
+    }
+
+    /**
      * The DisplayWhiteBalanceController decouples itself from its parent (DisplayPowerController)
      * by providing this interface to implement (and a method to set its callbacks object), and
      * calling these methods.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodDialogWindowContext.java b/services/core/java/com/android/server/inputmethod/InputMethodDialogWindowContext.java
new file mode 100644
index 0000000..1779333
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/InputMethodDialogWindowContext.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.inputmethod;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Provides the window context for the IME switcher dialog.
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public final class InputMethodDialogWindowContext {
+    @Nullable
+    private Context mDialogWindowContext;
+
+    /**
+     * Returns the window context for IME switch dialogs to receive configuration changes.
+     *
+     * This method initializes the window context if it was not initialized, or moves the context to
+     * the targeted display if the current display of context is different from the display
+     * specified by {@code displayId}.
+     */
+    @NonNull
+    @VisibleForTesting(visibility = PACKAGE)
+    public Context get(int displayId) {
+        if (mDialogWindowContext == null || mDialogWindowContext.getDisplayId() != displayId) {
+            final Context systemUiContext = ActivityThread.currentActivityThread()
+                    .getSystemUiContext(displayId);
+            final Context windowContext = systemUiContext.createWindowContext(
+                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */);
+            mDialogWindowContext = new ContextThemeWrapper(
+                    windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings);
+        }
+        return mDialogWindowContext;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8a6aa0d..feb0d138 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -203,7 +203,7 @@
 /**
  * This class provides a system service that manages input methods.
  */
-public class InputMethodManagerService extends IInputMethodManager.Stub
+public final class InputMethodManagerService extends IInputMethodManager.Stub
         implements Handler.Callback {
     static final boolean DEBUG = false;
     static final String TAG = "InputMethodManagerService";
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index fcb1be0..348bb2d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -16,22 +16,19 @@
 
 package com.android.server.inputmethod;
 
-import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 import static com.android.server.inputmethod.InputMethodManagerService.DEBUG;
 import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID;
 
-import android.app.ActivityThread;
+import android.annotation.Nullable;
 import android.app.AlertDialog;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.os.IBinder;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
-import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -45,7 +42,6 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
 import com.android.server.wm.WindowManagerInternal;
@@ -53,8 +49,7 @@
 import java.util.List;
 
 /** A controller to show/hide the input method menu */
-@VisibleForTesting(visibility = PACKAGE)
-public class InputMethodMenuController {
+final class InputMethodMenuController {
     private static final String TAG = InputMethodMenuController.class.getSimpleName();
 
     private final InputMethodManagerService mService;
@@ -64,17 +59,18 @@
     private final KeyguardManager mKeyguardManager;
     private final WindowManagerInternal mWindowManagerInternal;
 
-    private Context mSettingsContext;
     private AlertDialog.Builder mDialogBuilder;
     private AlertDialog mSwitchingDialog;
-    private IBinder mSwitchingDialogToken;
     private View mSwitchingDialogTitleView;
     private InputMethodInfo[] mIms;
     private int[] mSubtypeIds;
 
     private boolean mShowImeWithHardKeyboard;
 
-    @VisibleForTesting(visibility = PACKAGE)
+    @GuardedBy("ImfLock.class")
+    @Nullable
+    private InputMethodDialogWindowContext mDialogWindowContext;
+
     public InputMethodMenuController(InputMethodManagerService service) {
         mService = service;
         mSettings = mService.mSettings;
@@ -132,8 +128,11 @@
                 }
             }
 
-            final Context settingsContext = getSettingsContext(displayId);
-            mDialogBuilder = new AlertDialog.Builder(settingsContext);
+            if (mDialogWindowContext == null) {
+                mDialogWindowContext = new InputMethodDialogWindowContext();
+            }
+            final Context dialogWindowContext = mDialogWindowContext.get(displayId);
+            mDialogBuilder = new AlertDialog.Builder(dialogWindowContext);
             mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu());
 
             final Context dialogContext = mDialogBuilder.getContext();
@@ -199,7 +198,7 @@
             // Use an alternate token for the dialog for that window manager can group the token
             // with other IME windows based on type vs. grouping based on whichever token happens
             // to get selected by the system later on.
-            attrs.token = mSwitchingDialogToken;
+            attrs.token = dialogWindowContext.getWindowContextToken();
             attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
             attrs.setTitle("Select input method");
             w.setAttributes(attrs);
@@ -208,27 +207,6 @@
         }
     }
 
-    /**
-     * Returns the window context for IME switch dialogs to receive configuration changes.
-     *
-     * This method initializes the window context if it was not initialized. This method also moves
-     * the context to the targeted display if the current display of context is different than
-     * the display specified by {@code displayId}.
-     */
-    @VisibleForTesting
-    public Context getSettingsContext(int displayId) {
-        if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) {
-            final Context systemUiContext = ActivityThread.currentActivityThread()
-                    .getSystemUiContext(displayId);
-            final Context windowContext = systemUiContext.createWindowContext(
-                    WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */);
-            mSettingsContext = new ContextThemeWrapper(
-                    windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings);
-            mSwitchingDialogToken = mSettingsContext.getWindowContextToken();
-        }
-        return mSettingsContext;
-    }
-
     private boolean isScreenLocked() {
         return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()
                 && mKeyguardManager.isKeyguardSecure();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c01851a..fac7a40 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -100,7 +100,6 @@
 import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.NetworkTemplate.buildTemplateCarrierMetered;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
 import static android.os.Trace.TRACE_TAG_NETWORK;
 import static android.provider.Settings.Global.NETPOLICY_OVERRIDE_ENABLED;
@@ -182,7 +181,6 @@
 import android.net.NetworkStateSnapshot;
 import android.net.NetworkTemplate;
 import android.net.TelephonyNetworkSpecifier;
-import android.net.TrafficStats;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.BestClock;
@@ -2299,7 +2297,7 @@
         if (dataWarningConfig == WARNING_DISABLED) {
             return WARNING_DISABLED;
         } else {
-            return dataWarningConfig * MB_IN_BYTES;
+            return DataUnit.MEBIBYTES.toBytes(dataWarningConfig);
         }
     }
 
@@ -3468,9 +3466,9 @@
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_BILLED)
-                        .setDataUsage(1 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(1),
                                 ZonedDateTime.now().minusHours(36).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
@@ -3478,15 +3476,15 @@
                         .setTitle("G-Mobile Happy")
                         .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED,
                                 SubscriptionPlan.LIMIT_BEHAVIOR_BILLED)
-                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(5),
                                 ZonedDateTime.now().minusHours(36).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile, Charged after limit")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_BILLED)
-                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(5),
                                 ZonedDateTime.now().minusHours(36).toInstant().toEpochMilli())
                         .build());
             } else if ("month_soft".equals(fake)) {
@@ -3495,25 +3493,25 @@
                         .setTitle("G-Mobile is the carriers name who this plan belongs to")
                         .setSummary("Crazy unlimited bandwidth plan with incredibly long title "
                                 + "that should be cut off to prevent UI from looking terrible")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(1 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(1),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile, Throttled after limit")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(5),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile, No data connection after limit")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
-                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(5),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
 
@@ -3521,25 +3519,25 @@
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile is the carriers name who this plan belongs to")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(6 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(6),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile, Throttled after limit")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(5),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
                         .setTitle("G-Mobile, No data connection after limit")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
-                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataUsage(DataUnit.GIBIBYTES.toBytes(5),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
 
@@ -3553,9 +3551,9 @@
                         .createNonrecurring(ZonedDateTime.now().minusDays(20),
                                 ZonedDateTime.now().plusDays(10))
                         .setTitle("G-Mobile")
-                        .setDataLimit(512 * TrafficStats.MB_IN_BYTES,
+                        .setDataLimit(DataUnit.MEBIBYTES.toBytes(512),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
-                        .setDataUsage(100 * TrafficStats.MB_IN_BYTES,
+                        .setDataUsage(DataUnit.MEBIBYTES.toBytes(100),
                                 ZonedDateTime.now().minusHours(3).toInstant().toEpochMilli())
                         .build());
             } else if ("prepaid_crazy".equals(fake)) {
@@ -3563,9 +3561,9 @@
                         .createNonrecurring(ZonedDateTime.now().minusDays(20),
                                 ZonedDateTime.now().plusDays(10))
                         .setTitle("G-Mobile Anytime")
-                        .setDataLimit(512 * TrafficStats.MB_IN_BYTES,
+                        .setDataLimit(DataUnit.MEBIBYTES.toBytes(512),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
-                        .setDataUsage(100 * TrafficStats.MB_IN_BYTES,
+                        .setDataUsage(DataUnit.MEBIBYTES.toBytes(100),
                                 ZonedDateTime.now().minusHours(3).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
@@ -3573,9 +3571,9 @@
                                 ZonedDateTime.now().plusDays(20))
                         .setTitle("G-Mobile Nickel Nights")
                         .setSummary("5¢/GB between 1-5AM")
-                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(5),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(15 * TrafficStats.MB_IN_BYTES,
+                        .setDataUsage(DataUnit.MEBIBYTES.toBytes(15),
                                 ZonedDateTime.now().minusHours(30).toInstant().toEpochMilli())
                         .build());
                 plans.add(SubscriptionPlan.Builder
@@ -3583,9 +3581,9 @@
                                 ZonedDateTime.now().plusDays(20))
                         .setTitle("G-Mobile Bonus 3G")
                         .setSummary("Unlimited 3G data")
-                        .setDataLimit(1 * TrafficStats.GB_IN_BYTES,
+                        .setDataLimit(DataUnit.GIBIBYTES.toBytes(1),
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(300 * TrafficStats.MB_IN_BYTES,
+                        .setDataUsage(DataUnit.MEBIBYTES.toBytes(300),
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
             } else if ("unlimited".equals(fake)) {
@@ -3595,7 +3593,7 @@
                         .setTitle("G-Mobile Awesome")
                         .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED,
                                 SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
-                        .setDataUsage(50 * TrafficStats.MB_IN_BYTES,
+                        .setDataUsage(DataUnit.MEBIBYTES.toBytes(50),
                                 ZonedDateTime.now().minusHours(3).toInstant().toEpochMilli())
                         .build());
             }
diff --git a/services/core/java/com/android/server/notification/VibratorHelper.java b/services/core/java/com/android/server/notification/VibratorHelper.java
index 54dd113..e5d07bc 100644
--- a/services/core/java/com/android/server/notification/VibratorHelper.java
+++ b/services/core/java/com/android/server/notification/VibratorHelper.java
@@ -16,6 +16,9 @@
 
 package com.android.server.notification;
 
+import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
+import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,6 +33,7 @@
 import com.android.internal.R;
 import com.android.server.pm.PackageManagerService;
 
+import java.time.Duration;
 import java.util.Arrays;
 
 /**
@@ -89,8 +93,7 @@
      * Safely create a {@link VibrationEffect} from given waveform description.
      *
      * <p>The waveform is described by a sequence of values for target amplitude, frequency and
-     * duration, that are forwarded to
-     * {@link VibrationEffect.WaveformBuilder#addRamp(float, float, int)}.
+     * duration, that are forwarded to {@link VibrationEffect.WaveformBuilder#addTransition}.
      *
      * <p>This method returns {@code null} if the pattern is also {@code null} or invalid.
      *
@@ -114,16 +117,17 @@
 
             VibrationEffect.WaveformBuilder waveformBuilder = VibrationEffect.startWaveform();
             for (int i = 0; i < length; i += 3) {
-                waveformBuilder.addRamp(
-                        /* amplitude= */ values[i],
-                        /* frequencyHz= */ values[i + 1],
-                        /* duration= */ (int) values[i + 2]);
+                waveformBuilder.addTransition(Duration.ofMillis((int) values[i + 2]),
+                        targetAmplitude(values[i]), targetFrequency(values[i + 1]));
             }
 
+            VibrationEffect effect = waveformBuilder.build();
             if (insistent) {
-                return waveformBuilder.build(/* repeat= */ 0);
+                return VibrationEffect.startComposition()
+                        .repeatEffectIndefinitely(effect)
+                        .compose();
             }
-            return waveformBuilder.build();
+            return effect;
         } catch (IllegalArgumentException e) {
             Slog.e(TAG, "Error creating vibration PWLE waveform with pattern: "
                     + Arrays.toString(values));
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d9ade96..390dd3f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2264,10 +2264,6 @@
         }
 
         if (params.isStaged) {
-            // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
-            //  though ideally, we just need to send session committed broadcast.
-            sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
-
             mStagedSession.verifySession();
         } else {
             verify();
@@ -2514,6 +2510,7 @@
                 mStagedSession.notifyEndPreRebootVerification();
                 if (error == SessionInfo.SESSION_NO_ERROR) {
                     mStagingManager.commitSession(mStagedSession);
+                    sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
                 } else {
                     dispatchSessionFinished(INSTALL_FAILED_VERIFICATION_FAILURE, msg, null);
                     maybeFinishChildSessions(INSTALL_FAILED_VERIFICATION_FAILURE, msg);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index fd2256f..99f70b2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3563,18 +3563,27 @@
             }
             final LocalIntentReceiver receiver = new LocalIntentReceiver();
             session.commit(receiver.getIntentSender());
-            final Intent result = receiver.getResult();
-            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageInstaller.STATUS_FAILURE);
-            if (status == PackageInstaller.STATUS_SUCCESS) {
+            if (!session.isStaged()) {
+                final Intent result = receiver.getResult();
+                final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                        PackageInstaller.STATUS_FAILURE);
+                if (status == PackageInstaller.STATUS_SUCCESS) {
+                    if (logSuccess) {
+                        pw.println("Success");
+                    }
+                } else {
+                    pw.println("Failure ["
+                            + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+                }
+                return status;
+            } else {
+                // Return immediately without retrieving the result. The caller will decide
+                // whether to wait for the session to become ready.
                 if (logSuccess) {
                     pw.println("Success");
                 }
-            } else {
-                pw.println("Failure ["
-                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+                return PackageInstaller.STATUS_SUCCESS;
             }
-            return status;
         } finally {
             IoUtils.closeQuietly(session);
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 15e64df..72db242 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -35,8 +35,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.LocusId;
-import android.content.pm.AppSearchPerson;
 import android.content.pm.AppSearchShortcutInfo;
+import android.content.pm.AppSearchShortcutPerson;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
@@ -965,7 +965,7 @@
      */
     public ArraySet<String> getUsedBitmapFiles() {
         final ArraySet<String> usedFiles = new ArraySet<>(1);
-        forEachShortcut(AppSearchShortcutInfo.QUERY_HAS_BITMAP_PATH, si -> {
+        forEachShortcut(si -> {
             if (si.getBitmapPath() != null) {
                 usedFiles.add(getFileName(si.getBitmapPath()));
             }
@@ -1176,7 +1176,7 @@
 
         // Keep the previous IDs.
         final ArraySet<String> toDisableList = new ArraySet<>(1);
-        forEachShortcut(AppSearchShortcutInfo.QUERY_IS_MANIFEST, si -> {
+        forEachShortcut(si -> {
             if (si.isManifestShortcut()) {
                 toDisableList.add(si.getId());
             }
@@ -1319,7 +1319,7 @@
     private ArrayMap<ComponentName, ArrayList<ShortcutInfo>> sortShortcutsToActivities() {
         final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> activitiesToShortcuts
                 = new ArrayMap<>();
-        forEachShortcut(AppSearchShortcutInfo.QUERY_IS_NOT_FLOATING, si -> {
+        forEachShortcut(si -> {
             if (si.isFloating()) {
                 return; // Ignore floating shortcuts, which are not tied to any activities.
             }
@@ -1369,14 +1369,7 @@
         // (If it's for update, then don't count dynamic shortcuts, since they'll be replaced
         // anyway.)
         final ArrayMap<ComponentName, Integer> counts = new ArrayMap<>(4);
-        final String query;
-        if (operation != ShortcutService.OPERATION_SET) {
-            query = AppSearchShortcutInfo.QUERY_IS_MANIFEST + " OR "
-                    + AppSearchShortcutInfo.QUERY_IS_DYNAMIC;
-        } else {
-            query = AppSearchShortcutInfo.QUERY_IS_MANIFEST;
-        }
-        forEachShortcut(query, shortcut -> {
+        forEachShortcut(shortcut -> {
             if (shortcut.isManifestShortcut()) {
                 incrementCountForActivity(counts, shortcut.getActivity(), 1);
             } else if (shortcut.isDynamic() && (operation != ShortcutService.OPERATION_SET)) {
@@ -1539,7 +1532,7 @@
     /** @return true if there's any shortcuts that are not manifest shortcuts. */
     public boolean hasNonManifestShortcuts() {
         final boolean[] condition = new boolean[1];
-        forEachShortcutStopWhen(AppSearchShortcutInfo.QUERY_IS_NOT_MANIFEST, si -> {
+        forEachShortcutStopWhen(si -> {
             if (!si.isDeclaredInManifest()) {
                 condition[0] = true;
                 return true;
@@ -2287,12 +2280,7 @@
     }
 
     private void forEachShortcut(@NonNull final Consumer<ShortcutInfo> cb) {
-        forEachShortcut("", cb);
-    }
-
-    private void forEachShortcut(
-            @NonNull final String query, @NonNull final Consumer<ShortcutInfo> cb) {
-        forEachShortcutStopWhen(query, si -> {
+        forEachShortcutStopWhen(si -> {
             cb.accept(si);
             return false;
         });
@@ -2307,11 +2295,6 @@
 
     private void forEachShortcutStopWhen(
             @NonNull final Function<ShortcutInfo, Boolean> cb) {
-        forEachShortcutStopWhen("", cb);
-    }
-
-    private void forEachShortcutStopWhen(
-            @NonNull final String query, @NonNull final Function<ShortcutInfo, Boolean> cb) {
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
             if (cb.apply(si)) {
@@ -2328,12 +2311,12 @@
                     + " pkg=" + getPackageName());
         }
         SetSchemaRequest.Builder schemaBuilder = new SetSchemaRequest.Builder()
-                .addSchemas(AppSearchPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA)
+                .addSchemas(AppSearchShortcutPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA)
                 .setForceOverride(true);
         for (PackageIdentifier pi : mPackageIdentifiers.values()) {
             schemaBuilder = schemaBuilder
                     .setSchemaTypeVisibilityForPackage(
-                            AppSearchPerson.SCHEMA_TYPE, true, pi)
+                            AppSearchShortcutPerson.SCHEMA_TYPE, true, pi)
                     .setSchemaTypeVisibilityForPackage(
                             AppSearchShortcutInfo.SCHEMA_TYPE, true, pi);
         }
@@ -2403,8 +2386,8 @@
                     .addIds(ids).build(), mShortcutUser.mExecutor, result -> {
                     final List<ShortcutInfo> ret = result.getSuccesses().values()
                             .stream().map(doc ->
-                                    new AppSearchShortcutInfo(doc)
-                                            .toShortcutInfo(mShortcutUser.getUserId()))
+                                    ShortcutInfo.createFromGenericDocument(
+                                            mShortcutUser.getUserId(), doc))
                             .collect(Collectors.toList());
                     cb.accept(ret);
                 });
@@ -2480,8 +2463,8 @@
                 }
                 cb.complete(results.getResultValue().stream()
                         .map(SearchResult::getGenericDocument)
-                        .map(AppSearchShortcutInfo::new)
-                        .map(si -> si.toShortcutInfo(mShortcutUser.getUserId()))
+                        .map(doc -> ShortcutInfo.createFromGenericDocument(
+                                mShortcutUser.getUserId(), doc))
                         .collect(Collectors.toList()));
             });
         }));
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 057f8de..8393dee 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -41,7 +41,6 @@
 import android.content.IntentSender.SendIntentException;
 import android.content.LocusId;
 import android.content.pm.ActivityInfo;
-import android.content.pm.AppSearchShortcutInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.IPackageManager;
@@ -2805,28 +2804,6 @@
         }
     }
 
-    private String createQuery(final boolean matchDynamic, final boolean matchPinned,
-            final boolean matchManifest, final boolean matchCached) {
-
-        final List<String> queries = new ArrayList<>(1);
-        if (matchDynamic) {
-            queries.add(AppSearchShortcutInfo.QUERY_IS_DYNAMIC);
-        }
-        if (matchPinned) {
-            queries.add(AppSearchShortcutInfo.QUERY_IS_PINNED);
-        }
-        if (matchManifest) {
-            queries.add(AppSearchShortcutInfo.QUERY_IS_MANIFEST);
-        }
-        if (matchCached) {
-            queries.add(AppSearchShortcutInfo.QUERY_IS_CACHED);
-        }
-        if (queries.isEmpty()) {
-            return "";
-        }
-        return "(" + String.join(" OR ", queries) + ")";
-    }
-
     /**
      * Remove all the information associated with a package.  This will really remove all the
      * information, including the restore information (i.e. it'll remove packages even if they're
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 9b3d6d6..8e41c9b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -73,11 +73,6 @@
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.content.pm.SigningDetails;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedPermission;
-import com.android.server.pm.pkg.component.ParsedPermissionGroup;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
@@ -136,6 +131,10 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedPermissionUtils;
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.policy.SoftRestrictedPermissionPolicy;
 
@@ -3172,18 +3171,17 @@
                 }
             } else if (NOTIFICATION_PERMISSIONS.contains(newPerm)) {
                 //&& (origPs.getPermissionState(newPerm) == null) {
-                // TODO(b/205888750): add back line about origPs once propagated through droidfood
+                // TODO(b/205888750): add back line about origPs once all TODO sections below are
+                //  propagated through droidfood
                 Permission bp = mRegistry.getPermission(newPerm);
                 if (bp == null) {
                     throw new IllegalStateException("Unknown new permission " + newPerm);
                 }
-                // TODO(b/205888750): remove the line for REVOKE_WHEN_REQUESTED once propagated
-                //  through droidfood
                 if (!isUserSetOrPregrantedOrFixed(ps.getPermissionFlags(newPerm))) {
                     updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
-                    ps.updatePermissionFlags(bp, PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
-                                    | FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
-                            PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED);
+                    int setFlag = ps.isPermissionGranted(newPerm)
+                            ? 0 : FLAG_PERMISSION_REVIEW_REQUIRED;
+                    ps.updatePermissionFlags(bp, FLAG_PERMISSION_REVIEW_REQUIRED, setFlag);
                     // TODO(b/205888750): remove if/else block once propagated through droidfood
                     if (ps.isPermissionGranted(newPerm)
                             && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
@@ -3192,6 +3190,10 @@
                             && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
                         ps.grantPermission(bp);
                     }
+                } else {
+                    // TODO(b/205888750): remove once propagated through droidfood
+                    ps.updatePermissionFlags(bp, FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
+                            | FLAG_PERMISSION_REVIEW_REQUIRED, 0);
                 }
             }
         }
@@ -4779,9 +4781,10 @@
 
         // Handle REVIEW_REQUIRED
         if ((newFlags & priorityFixedMask) == 0) {
-            if (NOTIFICATION_PERMISSIONS.contains(srcState.getName())) {
+            if ((newFlags & (defaultGrantMask | userSettableMask)) == 0
+                    && NOTIFICATION_PERMISSIONS.contains(srcState.getName())) {
                 // For notification permissions, inherit from both states
-                // if no priority FIXED flags are set
+                // if no priority FIXED or DEFAULT_GRANT or USER_SET flags are set
                 newFlags |= (combinedFlags & FLAG_PERMISSION_REVIEW_REQUIRED);
             } else if ((newFlags & priorityMask) == 0) {
                 // Else inherit from destState if no priority flags are set
diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java
index 9127484..c1bfdf7 100644
--- a/services/core/java/com/android/server/power/PowerGroup.java
+++ b/services/core/java/com/android/server/power/PowerGroup.java
@@ -16,9 +16,16 @@
 
 package com.android.server.power;
 
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+import static android.os.PowerManagerInternal.isInteractive;
 
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.PowerManager;
+import android.os.Trace;
+import android.util.Slog;
 import android.view.Display;
 
 /**
@@ -31,47 +38,66 @@
  */
 public class PowerGroup {
     private static final String TAG = PowerGroup.class.getSimpleName();
+    private static final boolean DEBUG = false;
 
     private final DisplayPowerRequest mDisplayPowerRequest;
+    private final PowerGroupListener mWakefulnessListener;
     private final boolean mSupportsSandman;
     private final int mGroupId;
-
-    // True if DisplayManagerService has applied all the latest display states that were requested
-    // for this group
+    /** True if DisplayManagerService has applied all the latest display states that were requested
+     *  for this group. */
     private boolean mReady;
-    // True if this group is in the process of powering on
+    /** True if this group is in the process of powering on */
     private boolean mPoweringOn;
-    // True if this group is about to dream
+    /** True if this group is about to dream */
     private boolean mIsSandmanSummoned;
     private int mUserActivitySummary;
-    // The current wakefulness of this group
+    /** The current wakefulness of this group */
     private int mWakefulness;
     private int mWakeLockSummary;
     private long mLastPowerOnTime;
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
+    /** Timestamp (milliseconds since boot) of the last time the power group was awoken.*/
+    private long mLastWakeTime;
+    /** Timestamp (milliseconds since boot) of the last time the power group was put to sleep. */
+    private long mLastSleepTime;
 
-    PowerGroup(int groupId, DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready,
-            boolean supportsSandman) {
-        this.mGroupId = groupId;
-        this.mDisplayPowerRequest = displayPowerRequest;
-        this.mWakefulness = wakefulness;
-        this.mReady = ready;
-        this.mSupportsSandman = supportsSandman;
+    PowerGroup(int groupId, PowerGroupListener wakefulnessListener,
+            DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready,
+            boolean supportsSandman, long eventTime) {
+        mGroupId = groupId;
+        mWakefulnessListener = wakefulnessListener;
+        mDisplayPowerRequest = displayPowerRequest;
+        mWakefulness = wakefulness;
+        mReady = ready;
+        mSupportsSandman = supportsSandman;
+        mLastWakeTime = eventTime;
+        mLastSleepTime = eventTime;
     }
 
-    PowerGroup() {
-        this.mGroupId = Display.DEFAULT_DISPLAY_GROUP;
-        this.mDisplayPowerRequest = new DisplayPowerRequest();
-        this.mWakefulness = WAKEFULNESS_AWAKE;
-        this.mReady = false;
-        this.mSupportsSandman = true;
-    }
+    PowerGroup(int wakefulness, PowerGroupListener wakefulnessListener, long eventTime) {
+        mGroupId = Display.DEFAULT_DISPLAY_GROUP;
+        mWakefulnessListener = wakefulnessListener;
+        mDisplayPowerRequest = new DisplayPowerRequest();
+        mWakefulness = wakefulness;
+        mReady = false;
+        mSupportsSandman = true;
+        mLastWakeTime = eventTime;
+        mLastSleepTime = eventTime;    }
 
     DisplayPowerRequest getDisplayPowerRequestLocked() {
         return mDisplayPowerRequest;
     }
 
+    long getLastWakeTimeLocked() {
+        return mLastWakeTime;
+    }
+
+    long getLastSleepTimeLocked() {
+        return mLastSleepTime;
+    }
+
     int getWakefulnessLocked() {
         return mWakefulness;
     }
@@ -85,9 +111,19 @@
      *
      * @return {@code true} if the wakefulness value was changed; {@code false} otherwise.
      */
-    boolean setWakefulnessLocked(int newWakefulness) {
+    boolean setWakefulnessLocked(int newWakefulness, long eventTime, int uid, int reason, int opUid,
+            String opPackageName, String details) {
         if (mWakefulness != newWakefulness) {
+            if (newWakefulness == WAKEFULNESS_AWAKE) {
+                setLastPowerOnTimeLocked(eventTime);
+                setIsPoweringOnLocked(true);
+                mLastWakeTime = eventTime;
+            } else if (isInteractive(mWakefulness) && !isInteractive(newWakefulness)) {
+                mLastSleepTime = eventTime;
+            }
             mWakefulness = newWakefulness;
+            mWakefulnessListener.onWakefulnessChangedLocked(mGroupId, mWakefulness, eventTime,
+                    reason, uid, opUid, opPackageName, details);
             return true;
         }
         return false;
@@ -105,8 +141,9 @@
      * Sets whether the displays of this group are all ready.
      *
      * <p>A display is ready if its reported
-     * {@link DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged() actual state} matches
-     * its {@link DisplayManagerInternal#requestPowerState requested state}.
+     * {@link android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged()
+     * actual state} matches its
+     * {@link android.hardware.display.DisplayManagerInternal#requestPowerState requested state}.
      *
      * @param isReady {@code true} if every display in the group is ready; otherwise {@code false}.
      * @return {@code true} if the ready state changed; otherwise {@code false}.
@@ -148,6 +185,62 @@
         mIsSandmanSummoned = isSandmanSummoned;
     }
 
+    boolean dreamLocked(long eventTime, int uid) {
+        if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE) {
+            return false;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_POWER, "dreamPowerGroup" + getGroupId());
+        try {
+            Slog.i(TAG, "Napping power group (groupId=" + getGroupId() + ", uid=" + uid + ")...");
+            setSandmanSummonedLocked(true);
+            setWakefulnessLocked(WAKEFULNESS_DREAMING, eventTime, uid, /* reason= */0,
+                    /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_POWER);
+        }
+        return true;
+    }
+
+    boolean dozeLocked(long eventTime, int uid, int reason) {
+        if (eventTime < getLastWakeTimeLocked() || !isInteractive(mWakefulness)) {
+            return false;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOffDisplay");
+        try {
+            reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
+                    Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
+            Slog.i(TAG, "Powering off display group due to "
+                    + PowerManager.sleepReasonToString(reason)  + " (groupId= " + getGroupId()
+                    + ", uid= " + uid + ")...");
+
+            setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
+            setWakefulnessLocked(WAKEFULNESS_DOZING, eventTime, uid, reason, /* opUid= */ 0,
+                    /* opPackageName= */ null, /* details= */ null);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_POWER);
+        }
+        return true;
+    }
+
+    boolean sleepLocked(long eventTime, int uid, int reason) {
+        if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
+            return false;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_POWER, "sleepPowerGroup");
+        try {
+            Slog.i(TAG, "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ")...");
+            setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
+            setWakefulnessLocked(WAKEFULNESS_ASLEEP, eventTime, uid, reason, /* opUid= */0,
+                    /* opPackageName= */ null, /* details= */ null);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_POWER);
+        }
+        return true;
+    }
+
     long getLastUserActivityTimeLocked() {
         return mLastUserActivityTime;
     }
@@ -187,4 +280,22 @@
     public boolean supportsSandmanLocked() {
         return mSupportsSandman;
     }
+
+    protected interface PowerGroupListener {
+        /**
+         * Informs the recipient about a wakefulness change of a {@link PowerGroup}.
+         *
+         * @param groupId The PowerGroup's id for which the wakefulness has changed.
+         * @param wakefulness The new wakefulness.
+         * @param eventTime The time of the event.
+         * @param reason The reason, any of {@link android.os.PowerManager.WakeReason} or
+         *               {@link android.os.PowerManager.GoToSleepReason}.
+         * @param uid The uid which caused the wakefulness change.
+         * @param opUid The uid used for AppOps.
+         * @param opPackageName The Package name used for AppOps.
+         * @param details Details about the event.
+         */
+        void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime, int reason,
+                int uid, int opUid, String opPackageName, String details);
+    }
 }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index abfa016..4185b2d9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -29,6 +29,7 @@
 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
 import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
 import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+import static android.os.PowerManagerInternal.isInteractive;
 import static android.os.PowerManagerInternal.wakefulnessToString;
 
 import static com.android.internal.util.LatencyTracker.ACTION_TURN_ON_SCREEN;
@@ -338,12 +339,12 @@
     private boolean mRequestWaitForNegativeProximity;
 
     // Timestamp of the last time the device was awoken or put to sleep.
-    private long mLastWakeTime;
-    private long mLastSleepTime;
+    private long mLastGlobalWakeTime;
+    private long mLastGlobalSleepTime;
 
     // Last reason the device went to sleep.
-    private @WakeReason int mLastWakeReason;
-    private int mLastSleepReason;
+    private @WakeReason int mLastGlobalWakeReason;
+    private int mLastGlobalSleepReason;
 
     // Timestamp of last time power boost interaction was sent.
     private long mLastInteractivePowerHintTime;
@@ -352,6 +353,8 @@
     private long mLastScreenBrightnessBoostTime;
     private boolean mScreenBrightnessBoostInProgress;
 
+    private final PowerGroupWakefulnessChangeListener mPowerGroupWakefulnessChangeListener;
+
     // The suspend blocker used to keep the CPU alive while the device is booting.
     private final SuspendBlocker mBootingSuspendBlocker;
 
@@ -397,6 +400,10 @@
     // The current battery level percentage.
     private int mBatteryLevel;
 
+    // True if updatePowerStateLocked() is already in progress.
+    // TODO(b/215518989): Remove this once transactions are in place
+    private boolean mUpdatePowerStateInProgress;
+
     /**
      * The lock that should be held when interacting with {@link #mEnhancedDischargeTimeElapsed},
      * {@link #mLastEnhancedDischargeTimeUpdatedElapsed}, and
@@ -640,6 +647,23 @@
     // but the DreamService has not yet been told to start (it's an async process).
     private boolean mDozeStartInProgress;
 
+    private final class PowerGroupWakefulnessChangeListener implements
+            PowerGroup.PowerGroupListener {
+        @GuardedBy("mLock")
+        @Override
+        public void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime,
+                int reason, int uid, int opUid, String opPackageName, String details) {
+            if (wakefulness == WAKEFULNESS_AWAKE) {
+                // Kick user activity to prevent newly awake group from timing out instantly.
+                userActivityNoUpdateLocked(mPowerGroups.get(groupId), eventTime,
+                        PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+            }
+            mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
+            updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details);
+            updatePowerStateLocked();
+        }
+    }
+
     private final class DisplayGroupPowerChangeListener implements
             DisplayManagerInternal.DisplayGroupListener {
 
@@ -658,10 +682,12 @@
                 final boolean supportsSandman = groupId == Display.DEFAULT_DISPLAY_GROUP;
                 final PowerGroup powerGroup = new PowerGroup(
                         groupId,
+                        mPowerGroupWakefulnessChangeListener,
                         new DisplayPowerRequest(),
-                        getGlobalWakefulnessLocked(),
+                        WAKEFULNESS_AWAKE,
                         /* ready= */ false,
-                        supportsSandman);
+                        supportsSandman,
+                        mClock.uptimeMillis());
                 mPowerGroups.append(groupId, powerGroup);
                 onPowerGroupEventLocked(DISPLAY_GROUP_ADDED, powerGroup);
             }
@@ -992,6 +1018,8 @@
         mInattentiveSleepWarningOverlayController =
                 mInjector.createInattentiveSleepWarningController();
 
+        mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener();
+
         // Save brightness values:
         // Get float values from config.
         // Store float if valid
@@ -1144,10 +1172,10 @@
 
                 updatePowerStateLocked();
                 if (sQuiescent) {
-                    sleepDisplayGroupNoUpdateLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP),
+                    sleepPowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP),
                             mClock.uptimeMillis(),
                             PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
-                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+                            Process.SYSTEM_UID);
                 }
 
                 mContext.getSystemService(DeviceStateManager.class).registerCallback(
@@ -1164,7 +1192,9 @@
             mPolicy = getLocalService(WindowManagerPolicy.class);
             mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
             mAttentionDetector.systemReady(mContext);
-            mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP, new PowerGroup());
+            mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP,
+                    new PowerGroup(WAKEFULNESS_AWAKE, mPowerGroupWakefulnessChangeListener,
+                            mClock.uptimeMillis()));
             DisplayGroupPowerChangeListener displayGroupPowerChangeListener =
                     new DisplayGroupPowerChangeListener();
             mDisplayManagerInternal.registerDisplayGroupListener(displayGroupPowerChangeListener);
@@ -1503,7 +1533,7 @@
                 opUid = wakeLock.mOwnerUid;
             }
             for (int idx = 0; idx < mPowerGroups.size(); idx++) {
-                wakeDisplayGroupNoUpdateLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(),
+                wakePowerGroupLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(),
                         PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid, opPackageName,
                         opUid);
             }
@@ -1777,13 +1807,15 @@
     @GuardedBy("mLock")
     private boolean userActivityNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
             int event, int flags, int uid) {
+        final int groupId = powerGroup.getGroupId();
         if (DEBUG_SPEW) {
-            Slog.d(TAG, "userActivityNoUpdateLocked: groupId=" + powerGroup.getGroupId()
+            Slog.d(TAG, "userActivityNoUpdateLocked: groupId=" + groupId
                     + ", eventTime=" + eventTime + ", event=" + event
                     + ", flags=0x" + Integer.toHexString(flags) + ", uid=" + uid);
         }
 
-        if (eventTime < mLastSleepTime || eventTime < mLastWakeTime || !mSystemReady) {
+        if (eventTime < powerGroup.getLastSleepTimeLocked()
+                || eventTime < powerGroup.getLastWakeTimeLocked() || !mSystemReady) {
             return false;
         }
 
@@ -1801,7 +1833,6 @@
                 mUserInactiveOverrideFromWindowManager = false;
                 mOverriddenTimeout = -1;
             }
-
             final int wakefulness = powerGroup.getWakefulnessLocked();
             if (wakefulness == WAKEFULNESS_ASLEEP
                     || wakefulness == WAKEFULNESS_DOZING
@@ -1846,42 +1877,33 @@
         }
     }
 
-    private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
-            String details, int uid, String opPackageName, int opUid) {
-        synchronized (mLock) {
-            if (wakeDisplayGroupNoUpdateLocked(mPowerGroups.get(groupId), eventTime, reason,
-                    details, uid, opPackageName, opUid)) {
-                updatePowerStateLocked();
-            }
-        }
-    }
-
     @GuardedBy("mLock")
-    private boolean wakeDisplayGroupNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
+    private void wakePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
             @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
         final int groupId = powerGroup.getGroupId();
         if (DEBUG_SPEW) {
-            Slog.d(TAG, "wakeDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+            Slog.d(TAG, "wakePowerGroupLocked: eventTime=" + eventTime
                     + ", groupId=" + groupId + ", uid=" + uid);
         }
 
-        if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
-            return false;
+        if (eventTime < powerGroup.getLastSleepTimeLocked() || mForceSuspendActive
+                || !mSystemReady) {
+            return;
         }
 
-        final int currentState = powerGroup.getWakefulnessLocked();
-        if (currentState == WAKEFULNESS_AWAKE) {
+        final int currentWakefulness = powerGroup.getWakefulnessLocked();
+        if (currentWakefulness == WAKEFULNESS_AWAKE) {
             if (!mBootCompleted && sQuiescent) {
                 mDirty |= DIRTY_QUIESCENT;
-                return true;
+                updatePowerStateLocked();
             }
-            return false;
+            return;
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOnDisplay");
         try {
-            Slog.i(TAG, "Powering on display group from"
-                    + PowerManagerInternal.wakefulnessToString(currentState)
+            Slog.i(TAG, "Waking up power group from "
+                    + PowerManagerInternal.wakefulnessToString(currentWakefulness)
                     + " (groupId=" + groupId
                     + ", uid=" + uid
                     + ", reason=" + PowerManager.wakeReasonToString(reason)
@@ -1892,183 +1914,96 @@
             LatencyTracker.getInstance(mContext)
                     .onActionStart(ACTION_TURN_ON_SCREEN, String.valueOf(groupId));
 
-            setWakefulnessLocked(powerGroup, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
+            powerGroup.setWakefulnessLocked(WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
                     opPackageName, details);
-            powerGroup.setLastPowerOnTimeLocked(eventTime);
-            powerGroup.setIsPoweringOnLocked(true);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
         }
-
-        return true;
-    }
-
-    private void sleepDisplayGroup(int groupId, long eventTime, int reason, int flags,
-            int uid) {
-        synchronized (mLock) {
-            if (sleepDisplayGroupNoUpdateLocked(mPowerGroups.get(groupId), eventTime, reason, flags,
-                    uid)) {
-                updatePowerStateLocked();
-            }
-        }
     }
 
     @GuardedBy("mLock")
-    private boolean sleepDisplayGroupNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
-            int reason, int flags, int uid) {
+    private boolean dreamPowerGroupLocked(PowerGroup powerGroup, long eventTime, int uid) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "dreamPowerGroup: groupId=" + powerGroup.getGroupId() + ", eventTime="
+                    + eventTime + ", uid=" + uid);
+        }
+        if (!mBootCompleted || !mSystemReady) {
+            return false;
+        }
+        return powerGroup.dreamLocked(eventTime, uid);
+    }
+
+    @GuardedBy("mLock")
+    private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
+            int reason, int uid) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "sleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
                     + ", groupId=" + powerGroup.getGroupId() + ", reason=" + reason
-                    + ", flags=" + flags + ", uid=" + uid);
+                    + ", uid=" + uid);
         }
 
-        if (eventTime < mLastWakeTime
-                || !PowerManagerInternal.isInteractive(getWakefulnessLocked())
-                || !mSystemReady
-                || !mBootCompleted) {
+        if (!mSystemReady || !mBootCompleted) {
             return false;
         }
 
-        final int wakefulness = powerGroup.getWakefulnessLocked();
-        if (!PowerManagerInternal.isInteractive(wakefulness)) {
-            return false;
-        }
-
-        Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOffDisplay");
-        try {
-            reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
-                    Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
-            Slog.i(TAG, "Powering off display group due to "
-                    + PowerManager.sleepReasonToString(reason)
-                    + " (groupId= " + powerGroup.getGroupId() + ", uid= " + uid + ")...");
-
-            powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
-            setWakefulnessLocked(powerGroup, WAKEFULNESS_DOZING, eventTime, uid, reason,
-                    /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
-            if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
-                reallySleepDisplayGroupNoUpdateLocked(powerGroup, eventTime, uid);
-            }
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_POWER);
-        }
-        return true;
-    }
-
-    private void dreamDisplayGroup(int groupId, long eventTime, int uid) {
-        synchronized (mLock) {
-            if (dreamDisplayGroupNoUpdateLocked(mPowerGroups.get(groupId), eventTime, uid)) {
-                updatePowerStateLocked();
-            }
-        }
+        return powerGroup.dozeLocked(eventTime, uid, reason);
     }
 
     @GuardedBy("mLock")
-    private boolean dreamDisplayGroupNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
+    private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime, int reason,
             int uid) {
         if (DEBUG_SPEW) {
-            Slog.d(TAG, "dreamDisplayGroupNoUpdateLocked: eventTime=" + eventTime
-                    + ", uid=" + uid);
+            Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime + ", uid=" + uid);
         }
-
-        if (eventTime < mLastWakeTime || getWakefulnessLocked() != WAKEFULNESS_AWAKE
-                || !mBootCompleted || !mSystemReady) {
+        if (!mBootCompleted || !mSystemReady) {
             return false;
         }
 
-        Trace.traceBegin(Trace.TRACE_TAG_POWER, "napDisplayGroup");
-        try {
-            Slog.i(TAG, "Napping display group (groupId=" + powerGroup.getGroupId() + ", uid=" + uid
-                    + ")...");
-
-            powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
-            setWakefulnessLocked(powerGroup, WAKEFULNESS_DREAMING, eventTime, uid,
-                    /* reason= */0, /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
-
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_POWER);
-        }
-        return true;
-    }
-
-    @GuardedBy("mLock")
-    private boolean reallySleepDisplayGroupNoUpdateLocked(final PowerGroup powerGroup,
-            long eventTime, int uid) {
-        if (DEBUG_SPEW) {
-            Slog.d(TAG, "reallySleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
-                    + ", uid=" + uid);
-        }
-
-        if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
-                || !mBootCompleted || !mSystemReady
-                || powerGroup.getWakefulnessLocked()
-                == WAKEFULNESS_ASLEEP) {
-            return false;
-        }
-
-        Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallySleepDisplayGroup");
-        try {
-            Slog.i(TAG,
-                    "Sleeping display group (groupId=" + powerGroup.getGroupId() + ", uid=" + uid
-                            + ")...");
-
-            setWakefulnessLocked(powerGroup, WAKEFULNESS_ASLEEP, eventTime, uid,
-                    PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,  /* opUid= */ 0,
-                    /* opPackageName= */ null, /* details= */ null);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_POWER);
-        }
-        return true;
+        return powerGroup.sleepLocked(eventTime, uid, reason);
     }
 
     @VisibleForTesting
     @GuardedBy("mLock")
     void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
             int opUid, String opPackageName, String details) {
-        setWakefulnessLocked(mPowerGroups.get(groupId), wakefulness, eventTime, uid, reason, opUid,
+        mPowerGroups.get(groupId).setWakefulnessLocked(wakefulness, eventTime, uid, reason, opUid,
                 opPackageName, details);
     }
 
-    @GuardedBy("mLock")
-    private void setWakefulnessLocked(final PowerGroup powerGroup, int wakefulness, long eventTime,
-            int uid, int reason, int opUid, String opPackageName, String details) {
-        if (powerGroup.setWakefulnessLocked(wakefulness)) {
-            mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
-            setGlobalWakefulnessLocked(getGlobalWakefulnessLocked(),
-                    eventTime, reason, uid, opUid, opPackageName, details);
-            if (wakefulness == WAKEFULNESS_AWAKE) {
-                // Kick user activity to prevent newly awake group from timing out instantly.
-                userActivityNoUpdateLocked(powerGroup, eventTime,
-                        PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
-            }
-        }
-    }
-
     @SuppressWarnings("deprecation")
     @GuardedBy("mLock")
-    private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
+    private void updateGlobalWakefulnessLocked(long eventTime, int reason, int uid,
             int opUid, String opPackageName, String details) {
-        if (getWakefulnessLocked() == wakefulness) {
+        int newWakefulness = recalculateGlobalWakefulnessLocked();
+        int currentWakefulness = getGlobalWakefulnessLocked();
+        if (currentWakefulness == newWakefulness) {
             return;
         }
 
         // Phase 1: Handle pre-wakefulness change bookkeeping.
         final String traceMethodName;
-        switch (wakefulness) {
+        switch (newWakefulness) {
             case WAKEFULNESS_ASLEEP:
                 traceMethodName = "reallyGoToSleep";
                 Slog.i(TAG, "Sleeping (uid " + uid + ")...");
+                // TODO(b/215518989): Remove this once transactions are in place
+                if (currentWakefulness != WAKEFULNESS_DOZING) {
+                    // in case we are going to sleep without dozing before
+                    mLastGlobalSleepTime = eventTime;
+                    mLastGlobalSleepReason = reason;
+                }
                 break;
 
             case WAKEFULNESS_AWAKE:
                 traceMethodName = "wakeUp";
                 Slog.i(TAG, "Waking up from "
-                        + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+                        + PowerManagerInternal.wakefulnessToString(currentWakefulness)
                         + " (uid=" + uid
                         + ", reason=" + PowerManager.wakeReasonToString(reason)
                         + ", details=" + details
                         + ")...");
-                mLastWakeTime = eventTime;
-                mLastWakeReason = reason;
+                mLastGlobalWakeTime = eventTime;
+                mLastGlobalWakeReason = reason;
                 break;
 
             case WAKEFULNESS_DREAMING:
@@ -2081,13 +2016,13 @@
                 Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
                         + " (uid " + uid + ")...");
 
-                mLastSleepTime = eventTime;
-                mLastSleepReason = reason;
+                mLastGlobalSleepTime = eventTime;
+                mLastGlobalSleepReason = reason;
                 mDozeStartInProgress = true;
                 break;
 
             default:
-                throw new IllegalArgumentException("Unexpected wakefulness: " + wakefulness);
+                throw new IllegalArgumentException("Unexpected wakefulness: " + newWakefulness);
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
@@ -2095,20 +2030,20 @@
             // Phase 2: Handle wakefulness change and bookkeeping.
             // Under lock, invalidate before set ensures caches won't return stale values.
             mInjector.invalidateIsInteractiveCaches();
-            mWakefulnessRaw = wakefulness;
+            mWakefulnessRaw = newWakefulness;
             mWakefulnessChanging = true;
             mDirty |= DIRTY_WAKEFULNESS;
 
             // This is only valid while we are in wakefulness dozing. Set to false otherwise.
-            mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
+            mDozeStartInProgress &= (newWakefulness == WAKEFULNESS_DOZING);
 
             if (mNotifier != null) {
-                mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
+                mNotifier.onWakefulnessChangeStarted(newWakefulness, reason, eventTime);
             }
-            mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
+            mAttentionDetector.onWakefulnessChangeStarted(newWakefulness);
 
             // Phase 3: Handle post-wakefulness change bookkeeping.
-            switch (wakefulness) {
+            switch (newWakefulness) {
                 case WAKEFULNESS_AWAKE:
                     mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
                     if (sQuiescent) {
@@ -2116,7 +2051,13 @@
                     }
                     break;
 
+                case WAKEFULNESS_ASLEEP:
+                    // fallthrough
                 case WAKEFULNESS_DOZING:
+                    if (!isInteractive(currentWakefulness)) {
+                        // TODO(b/215518989): remove this once transactions are in place
+                        break;
+                    }
                     // Report the number of wake locks that will be cleared by going to sleep.
                     int numWakeLocksCleared = 0;
                     final int numWakeLocks = mWakeLocks.size();
@@ -2140,7 +2081,7 @@
 
     @VisibleForTesting
     @GuardedBy("mLock")
-    int getWakefulnessLocked() {
+    int getGlobalWakefulnessLocked() {
         return mWakefulnessRaw;
     }
 
@@ -2163,10 +2104,9 @@
      * </ol>
      */
     @GuardedBy("mLock")
-    int getGlobalWakefulnessLocked() {
-        final int size = mPowerGroups.size();
+    int recalculateGlobalWakefulnessLocked() {
         int deviceWakefulness = WAKEFULNESS_ASLEEP;
-        for (int i = 0; i < size; i++) {
+        for (int i = 0; i < mPowerGroups.size(); i++) {
             final int wakefulness = mPowerGroups.valueAt(i).getWakefulnessLocked();
             if (wakefulness == WAKEFULNESS_AWAKE) {
                 return WAKEFULNESS_AWAKE;
@@ -2187,10 +2127,10 @@
     void onPowerGroupEventLocked(int event, PowerGroup powerGroup) {
         final int groupId = powerGroup.getGroupId();
         if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) {
-            mPowerGroups.remove(groupId);
+            mPowerGroups.delete(groupId);
         }
-        final int oldWakefulness = getWakefulnessLocked();
-        final int newWakefulness = getGlobalWakefulnessLocked();
+        final int oldWakefulness = getGlobalWakefulnessLocked();
+        final int newWakefulness = recalculateGlobalWakefulnessLocked();
 
         if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_ADDED
                 && newWakefulness == WAKEFULNESS_AWAKE) {
@@ -2215,13 +2155,9 @@
                 default:
                     reason = 0;
             }
-
-            setGlobalWakefulnessLocked(
-                    getGlobalWakefulnessLocked(),
-                    mClock.uptimeMillis(), reason, Process.SYSTEM_UID, Process.SYSTEM_UID,
-                    mContext.getOpPackageName(), "groupId: " + groupId);
+            updateGlobalWakefulnessLocked(mClock.uptimeMillis(), reason, Process.SYSTEM_UID,
+                    Process.SYSTEM_UID, mContext.getOpPackageName(), "groupId: " + groupId);
         }
-
         mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
         updatePowerStateLocked();
     }
@@ -2243,15 +2179,15 @@
     @GuardedBy("mLock")
     private void finishWakefulnessChangeIfNeededLocked() {
         if (mWakefulnessChanging && areAllDisplaysReadyLocked()) {
-            if (getWakefulnessLocked() == WAKEFULNESS_DOZING
+            if (getGlobalWakefulnessLocked() == WAKEFULNESS_DOZING
                     && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
                 return; // wait until dream has enabled dozing
             } else {
                 // Doze wakelock acquired (doze started) or device is no longer dozing.
                 mDozeStartInProgress = false;
             }
-            if (getWakefulnessLocked() == WAKEFULNESS_DOZING
-                    || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
+            if (getGlobalWakefulnessLocked() == WAKEFULNESS_DOZING
+                    || getGlobalWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
                 logSleepTimeoutRecapturedLocked();
             }
             mWakefulnessChanging = false;
@@ -2282,7 +2218,7 @@
      */
     @GuardedBy("mLock")
     private void updatePowerStateLocked() {
-        if (!mSystemReady || mDirty == 0) {
+        if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) {
             return;
         }
         if (!Thread.holdsLock(mLock)) {
@@ -2290,6 +2226,7 @@
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
+        mUpdatePowerStateInProgress = true;
         try {
             // Phase 0: Basic state updates.
             updateIsPoweredLocked(mDirty);
@@ -2332,6 +2269,7 @@
             updateSuspendBlockerLocked();
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
+            mUpdatePowerStateInProgress = false;
         }
     }
 
@@ -2397,7 +2335,7 @@
                 final long now = mClock.uptimeMillis();
                 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
                         dockedOnWirelessCharger)) {
-                    wakeDisplayGroupNoUpdateLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP),
+                    wakePowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP),
                             now, PowerManager.WAKE_REASON_PLUGGED_IN,
                             "android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
                             mContext.getOpPackageName(), Process.SYSTEM_UID);
@@ -2446,7 +2384,7 @@
         }
 
         // If already dreaming and becoming powered, then don't wake.
-        if (mIsPowered && getWakefulnessLocked() == WAKEFULNESS_DREAMING) {
+        if (mIsPowered && getGlobalWakefulnessLocked() == WAKEFULNESS_DREAMING) {
             return false;
         }
 
@@ -2456,7 +2394,7 @@
         }
 
         // On Always On Display, SystemUI shows the charging indicator
-        if (mAlwaysOnEnabled && getWakefulnessLocked() == WAKEFULNESS_DOZING) {
+        if (mAlwaysOnEnabled && getGlobalWakefulnessLocked() == WAKEFULNESS_DOZING) {
             return false;
         }
 
@@ -2540,24 +2478,23 @@
 
             for (int idx = 0; idx < mPowerGroups.size(); idx++) {
                 final PowerGroup powerGroup = mPowerGroups.valueAt(idx);
-                final int wakeLockSummary = adjustWakeLockSummary(
-                        powerGroup.getWakefulnessLocked(),
+                final int wakeLockSummary = adjustWakeLockSummary(powerGroup.getWakefulnessLocked(),
                         invalidGroupWakeLockSummary | powerGroup.getWakeLockSummaryLocked());
                 powerGroup.setWakeLockSummaryLocked(wakeLockSummary);
             }
 
-            mWakeLockSummary = adjustWakeLockSummary(getWakefulnessLocked(),
+            mWakeLockSummary = adjustWakeLockSummary(getGlobalWakefulnessLocked(),
                     mWakeLockSummary);
 
             for (int i = 0; i < numProfiles; i++) {
                 final ProfilePowerState profile = mProfilePowerState.valueAt(i);
-                profile.mWakeLockSummary = adjustWakeLockSummary(getWakefulnessLocked(),
+                profile.mWakeLockSummary = adjustWakeLockSummary(getGlobalWakefulnessLocked(),
                         profile.mWakeLockSummary);
             }
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
-                        + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+                        + PowerManagerInternal.wakefulnessToString(getGlobalWakefulnessLocked())
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
             }
         }
@@ -2706,11 +2643,12 @@
             int groupUserActivitySummary = 0;
             long groupNextTimeout = 0;
             final PowerGroup powerGroup = mPowerGroups.valueAt(idx);
-            if (powerGroup.getWakefulnessLocked() != WAKEFULNESS_ASLEEP) {
+            final int wakefulness = powerGroup.getWakefulnessLocked();
+            if (wakefulness != WAKEFULNESS_ASLEEP) {
                 final long lastUserActivityTime = powerGroup.getLastUserActivityTimeLocked();
                 final long lastUserActivityTimeNoChangeLights =
                         powerGroup.getLastUserActivityTimeNoChangeLightsLocked();
-                if (lastUserActivityTime >= mLastWakeTime) {
+                if (lastUserActivityTime >= powerGroup.getLastWakeTimeLocked()) {
                     groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration;
                     if (now < groupNextTimeout) {
                         groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
@@ -2721,8 +2659,8 @@
                         }
                     }
                 }
-                if (groupUserActivitySummary == 0
-                        && lastUserActivityTimeNoChangeLights >= mLastWakeTime) {
+                if (groupUserActivitySummary == 0 && lastUserActivityTimeNoChangeLights
+                        >= powerGroup.getLastWakeTimeLocked()) {
                     groupNextTimeout = lastUserActivityTimeNoChangeLights + screenOffTimeout;
                     if (now < groupNextTimeout) {
                         final DisplayPowerRequest displayPowerRequest =
@@ -2740,7 +2678,7 @@
                     if (sleepTimeout >= 0) {
                         final long anyUserActivity = Math.max(lastUserActivityTime,
                                 lastUserActivityTimeNoChangeLights);
-                        if (anyUserActivity >= mLastWakeTime) {
+                        if (anyUserActivity >= powerGroup.getLastWakeTimeLocked()) {
                             groupNextTimeout = anyUserActivity + sleepTimeout;
                             if (now < groupNextTimeout) {
                                 groupUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
@@ -2786,7 +2724,7 @@
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateUserActivitySummaryLocked: groupId=" + powerGroup.getGroupId()
-                        + ", mWakefulness=" + wakefulnessToString(powerGroup.getWakefulnessLocked())
+                        + ", mWakefulness=" + wakefulnessToString(wakefulness)
                         + ", mUserActivitySummary=0x" + Integer.toHexString(
                         groupUserActivitySummary)
                         + ", nextTimeout=" + TimeUtils.formatUptime(groupNextTimeout));
@@ -2884,7 +2822,7 @@
             return false;
         }
 
-        if (getWakefulnessLocked() != WAKEFULNESS_AWAKE) {
+        if (getGlobalWakefulnessLocked() != WAKEFULNESS_AWAKE) {
             mInattentiveSleepWarningOverlayController.dismiss(false);
             return true;
         } else if (attentiveTimeout < 0 || isBeingKeptFromInattentiveSleepLocked()
@@ -3024,14 +2962,13 @@
                 if (DEBUG) {
                     Slog.i(TAG, "Going to sleep now due to long user inactivity");
                 }
-                changed = sleepDisplayGroupNoUpdateLocked(powerGroup, time,
-                        PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
-                        PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+                changed = sleepPowerGroupLocked(powerGroup, time,
+                        PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, Process.SYSTEM_UID);
             } else if (shouldNapAtBedTimeLocked()) {
-                changed = dreamDisplayGroupNoUpdateLocked(powerGroup, time, Process.SYSTEM_UID);
+                changed = dreamPowerGroupLocked(powerGroup, time, Process.SYSTEM_UID);
             } else {
-                changed = sleepDisplayGroupNoUpdateLocked(powerGroup, time,
-                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+                changed = dozePowerGroupLocked(powerGroup, time,
+                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, Process.SYSTEM_UID);
             }
         }
         return changed;
@@ -3228,25 +3165,27 @@
 
                 // Dream has ended or will be stopped.  Update the power state.
                 if (isItBedTimeYetLocked(powerGroup)) {
-                    final int flags = isAttentiveTimeoutExpired(powerGroup, now)
-                            ? PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE : 0;
-                    sleepDisplayGroupNoUpdateLocked(powerGroup, now,
-                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags, Process.SYSTEM_UID);
+                    if (isAttentiveTimeoutExpired(powerGroup, now)) {
+                        sleepPowerGroupLocked(powerGroup, now,
+                                PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, Process.SYSTEM_UID);
+                    } else {
+                        dozePowerGroupLocked(powerGroup, now,
+                                PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, Process.SYSTEM_UID);
+                    }
                 } else {
-                    wakeDisplayGroupNoUpdateLocked(powerGroup, now,
+                    wakePowerGroupLocked(powerGroup, now,
                             PowerManager.WAKE_REASON_UNKNOWN,
                             "android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
                             mContext.getOpPackageName(), Process.SYSTEM_UID);
                 }
-                updatePowerStateLocked();
             } else if (wakefulness == WAKEFULNESS_DOZING) {
                 if (isDreaming) {
                     return; // continue dozing
                 }
 
                 // Doze has ended or will be stopped.  Update the power state.
-                reallySleepDisplayGroupNoUpdateLocked(powerGroup, now, Process.SYSTEM_UID);
-                updatePowerStateLocked();
+                sleepPowerGroupLocked(powerGroup, now,  PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
+                        Process.SYSTEM_UID);
             }
         }
 
@@ -3263,7 +3202,7 @@
     private boolean canDreamLocked(final PowerGroup powerGroup) {
         final DisplayPowerRequest displayPowerRequest = powerGroup.getDisplayPowerRequestLocked();
         if (!mBootCompleted
-                || getWakefulnessLocked() != WAKEFULNESS_DREAMING
+                || getGlobalWakefulnessLocked() != WAKEFULNESS_DREAMING
                 || !mDreamsSupportedConfig
                 || !mDreamsEnabledSetting
                 || !displayPowerRequest.isBrightOrDim()
@@ -3294,7 +3233,7 @@
     @GuardedBy("mLock")
     private boolean canDozeLocked() {
         // TODO (b/175764708): Support per-display doze.
-        return getWakefulnessLocked() == WAKEFULNESS_DOZING;
+        return getGlobalWakefulnessLocked() == WAKEFULNESS_DOZING;
     }
 
     /**
@@ -3375,15 +3314,15 @@
 
                 final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
                         displayPowerRequest, mRequestWaitForNegativeProximity);
-                mNotifier.onScreenPolicyUpdate(groupId, displayPowerRequest.policy);
+                mNotifier.onScreenPolicyUpdate(powerGroup.getGroupId(), displayPowerRequest.policy);
+                int wakefulness = powerGroup.getWakefulnessLocked();
 
                 if (DEBUG_SPEW) {
                     Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
                             + ", groupId=" + groupId
                             + ", policy=" + policyToString(displayPowerRequest.policy)
                             + ", mWakefulness="
-                            + PowerManagerInternal.wakefulnessToString(
-                            powerGroup.getWakefulnessLocked())
+                            + PowerManagerInternal.wakefulnessToString(wakefulness)
                             + ", mWakeLockSummary=0x" + Integer.toHexString(
                             powerGroup.getWakeLockSummaryLocked())
                             + ", mUserActivitySummary=0x" + Integer.toHexString(
@@ -3401,7 +3340,7 @@
                 final boolean displayReadyStateChanged = powerGroup.setReadyLocked(ready);
                 final boolean poweringOn = powerGroup.isPoweringOnLocked();
                 if (ready && displayReadyStateChanged && poweringOn
-                        && powerGroup.getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
+                        && wakefulness == WAKEFULNESS_AWAKE) {
                     powerGroup.setIsPoweringOnLocked(false);
                     LatencyTracker.getInstance(mContext).onActionEnd(ACTION_TURN_ON_SCREEN);
                     Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
@@ -3424,7 +3363,7 @@
             if (mScreenBrightnessBoostInProgress) {
                 final long now = mClock.uptimeMillis();
                 mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
-                if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
+                if (mLastScreenBrightnessBoostTime > mLastGlobalSleepTime) {
                     final long boostTimeout = mLastScreenBrightnessBoostTime +
                             SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
                     if (boostTimeout > now) {
@@ -3656,7 +3595,7 @@
         // Here we wait for mWakefulnessChanging to become false since the wakefulness
         // transition to DOZING isn't considered "changed" until the doze wake lock is
         // acquired.
-        if (getWakefulnessLocked() == WAKEFULNESS_DOZING && mDozeStartInProgress) {
+        if (getGlobalWakefulnessLocked() == WAKEFULNESS_DOZING && mDozeStartInProgress) {
             return true;
         }
 
@@ -3721,7 +3660,7 @@
 
     private boolean isInteractiveInternal() {
         synchronized (mLock) {
-            return PowerManagerInternal.isInteractive(getWakefulnessLocked());
+            return PowerManagerInternal.isInteractive(getGlobalWakefulnessLocked());
         }
     }
 
@@ -4092,7 +4031,7 @@
 
     private void boostScreenBrightnessInternal(long eventTime, int uid) {
         synchronized (mLock) {
-            if (!mSystemReady || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
+            if (!mSystemReady || getGlobalWakefulnessLocked() == WAKEFULNESS_ASLEEP
                     || eventTime < mLastScreenBrightnessBoostTime) {
                 return;
             }
@@ -4225,14 +4164,9 @@
             synchronized (mLock) {
                 mForceSuspendActive = true;
                 // Place the system in an non-interactive state
-                boolean updatePowerState = false;
                 for (int idx = 0; idx < mPowerGroups.size(); idx++) {
-                    updatePowerState |= sleepDisplayGroupNoUpdateLocked(mPowerGroups.valueAt(idx),
-                            mClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
-                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
-                }
-                if (updatePowerState) {
-                    updatePowerStateLocked();
+                    sleepPowerGroupLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(),
+                            PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND, uid);
                 }
 
                 // Disable all the partial wake locks as well
@@ -4331,7 +4265,7 @@
             mConstants.dump(pw);
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
             pw.println("  mWakefulness="
-                    + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked()));
+                    + PowerManagerInternal.wakefulnessToString(getGlobalWakefulnessLocked()));
             pw.println("  mWakefulnessChanging=" + mWakefulnessChanging);
             pw.println("  mIsPowered=" + mIsPowered);
             pw.println("  mPlugType=" + mPlugType);
@@ -4382,9 +4316,10 @@
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
             pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
-            pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
-            pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
-            pw.println("  mLastSleepReason=" + PowerManager.sleepReasonToString(mLastSleepReason));
+            pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastGlobalWakeTime));
+            pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastGlobalSleepTime));
+            pw.println("  mLastSleepReason=" + PowerManager.sleepReasonToString(
+                    mLastGlobalSleepReason));
             pw.println("  mLastInteractivePowerHintTime="
                     + TimeUtils.formatUptime(mLastInteractivePowerHintTime));
             pw.println("  mLastScreenBrightnessBoostTime="
@@ -4565,7 +4500,7 @@
         synchronized (mLock) {
             mConstants.dumpProto(proto);
             proto.write(PowerManagerServiceDumpProto.DIRTY, mDirty);
-            proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, getWakefulnessLocked());
+            proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, getGlobalWakefulnessLocked());
             proto.write(PowerManagerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging);
             proto.write(PowerManagerServiceDumpProto.IS_POWERED, mIsPowered);
             proto.write(PowerManagerServiceDumpProto.PLUG_TYPE, mPlugType);
@@ -4664,8 +4599,8 @@
                 proto.write(PowerManagerServiceDumpProto.DEVICE_IDLE_TEMP_WHITELIST, id);
             }
 
-            proto.write(PowerManagerServiceDumpProto.LAST_WAKE_TIME_MS, mLastWakeTime);
-            proto.write(PowerManagerServiceDumpProto.LAST_SLEEP_TIME_MS, mLastSleepTime);
+            proto.write(PowerManagerServiceDumpProto.LAST_WAKE_TIME_MS, mLastGlobalWakeTime);
+            proto.write(PowerManagerServiceDumpProto.LAST_SLEEP_TIME_MS, mLastGlobalSleepTime);
             proto.write(
                     PowerManagerServiceDumpProto.LAST_INTERACTIVE_POWER_HINT_TIME_MS,
                     mLastInteractivePowerHintTime);
@@ -5505,8 +5440,10 @@
             final int uid = Binder.getCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                wakeDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, details, uid,
-                        opPackageName, uid);
+                synchronized (mLock) {
+                    wakePowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP), eventTime,
+                            reason, details, uid, opPackageName, uid);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -5524,7 +5461,14 @@
             final int uid = Binder.getCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                sleepDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, flags, uid);
+                synchronized (mLock) {
+                    PowerGroup defaultPowerGroup = mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP);
+                    if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
+                        sleepPowerGroupLocked(defaultPowerGroup, eventTime, reason, uid);
+                    } else {
+                        dozePowerGroupLocked(defaultPowerGroup, eventTime, reason, uid);
+                    }
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -5542,7 +5486,10 @@
             final int uid = Binder.getCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                dreamDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, uid);
+                synchronized (mLock) {
+                    dreamPowerGroupLocked(mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP),
+                            eventTime, uid);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -6181,13 +6128,15 @@
 
     private int getLastSleepReasonInternal() {
         synchronized (mLock) {
-            return mLastSleepReason;
+            return mLastGlobalSleepReason;
         }
     }
 
+    @VisibleForTesting
     private PowerManager.WakeData getLastWakeupInternal() {
         synchronized (mLock) {
-            return new WakeData(mLastWakeTime, mLastWakeReason, mLastWakeTime - mLastSleepTime);
+            return new WakeData(mLastGlobalWakeTime, mLastGlobalWakeReason,
+                    mLastGlobalWakeTime - mLastGlobalSleepTime);
         }
     }
 
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index e180032..277d802 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -23,13 +23,13 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkIdentity.OEM_PAID;
-import static android.net.NetworkIdentity.OEM_PRIVATE;
 import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkTemplate.MATCH_ETHERNET;
 import static android.net.NetworkTemplate.MATCH_MOBILE;
 import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_PAID;
+import static android.net.NetworkTemplate.OEM_MANAGED_PRIVATE;
 import static android.net.NetworkTemplate.getAllCollapsedRatTypes;
 import static android.os.Debug.getIonHeapsSizeKb;
 import static android.os.Process.LAST_SHARED_APPLICATION_GID;
@@ -1292,7 +1292,8 @@
                 new Pair(MATCH_MOBILE, TRANSPORT_CELLULAR),
                 new Pair(MATCH_WIFI, TRANSPORT_WIFI)
         );
-        final int[] oemManagedTypes = new int[] {OEM_PAID | OEM_PRIVATE, OEM_PAID, OEM_PRIVATE};
+        final int[] oemManagedTypes = new int[] {OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
+                OEM_MANAGED_PAID, OEM_MANAGED_PRIVATE};
 
         final List<NetworkStatsExt> ret = new ArrayList<>();
 
@@ -1368,12 +1369,12 @@
                 NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats);
         if (!includeTags) return nonTaggedStats;
 
-        final android.app.usage.NetworkStats quaryTaggedStats =
+        final android.app.usage.NetworkStats queryTaggedStats =
                 mNetworkStatsManager.queryTaggedSummary(template,
                 currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
                 currentTimeInMillis);
         final NetworkStats taggedStats =
-                NetworkStatsUtils.fromPublicNetworkStats(quaryTaggedStats);
+                NetworkStatsUtils.fromPublicNetworkStats(queryTaggedStats);
         return nonTaggedStats.add(taggedStats);
     }
 
@@ -1470,7 +1471,7 @@
      */
     @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
             @NonNull Function<NetworkStats.Entry, NetworkStats.Entry> slicer) {
-        NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1);
+        NetworkStats ret = new NetworkStats(0, 1);
         NetworkStats.Entry entry = new NetworkStats.Entry();
         for (NetworkStats.Entry e : stats) {
             if (slicer != null) {
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index b3649a7..53a9244 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -134,7 +134,12 @@
 
         for (ResolveInfo ri : services) {
             ServiceInfo si = ri.serviceInfo;
-            // TODO: add BIND_TV_INTERACTIVE_APP permission and check it here
+            if (!android.Manifest.permission.BIND_TV_INTERACTIVE_APP.equals(si.permission)) {
+                Slog.w(TAG, "Skipping TV interactiva app service " + si.name
+                        + ": it does not require the permission "
+                        + android.Manifest.permission.BIND_TV_INTERACTIVE_APP);
+                continue;
+            }
 
             ComponentName component = new ComponentName(si.packageName, si.name);
             try {
@@ -788,10 +793,12 @@
                                 componentName, tiasId, resolvedUserId);
                         serviceState.addPendingAppLinkCommand(command);
                         userState.mServiceStateMap.put(componentName, serviceState);
+                        updateServiceConnectionLocked(componentName, resolvedUserId);
                     } else if (serviceState.mService != null) {
                         serviceState.mService.sendAppLinkCommand(command);
                     } else {
                         serviceState.addPendingAppLinkCommand(command);
+                        updateServiceConnectionLocked(componentName, resolvedUserId);
                     }
                 }
             } catch (RemoteException e) {
@@ -1673,7 +1680,8 @@
 
         boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
                 || (serviceState.mPendingPrepare)
-                || (!serviceState.mPendingAppLinkInfo.isEmpty());
+                || (!serviceState.mPendingAppLinkInfo.isEmpty())
+                || (!serviceState.mPendingAppLinkCommand.isEmpty());
 
         if (serviceState.mService == null && shouldBind) {
             // This means that the service is not yet connected but its state indicates that we
@@ -2092,7 +2100,7 @@
 
         @Override
         public void onCommandRequest(
-                @TvInteractiveAppService.InteractiveAppServiceCommandType String cmdType,
+                @TvInteractiveAppService.PlaybackCommandType String cmdType,
                 Bundle parameters) {
             synchronized (mLock) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index eafd9d7..6c5d952 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -179,7 +179,7 @@
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
-                    ActivityManager.PROCESS_STATE_UNKNOWN, mContext.getOpPackageName());
+                    ActivityManager.PROCESS_STATE_UNKNOWN, null);
         } catch (RemoteException e) {
             // ignored; both services live in system_server
         }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index a95b6c9..b2e34da 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -16,6 +16,9 @@
 
 package com.android.server.vibrator;
 
+import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
+import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -65,6 +68,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -1711,7 +1715,8 @@
             long duration = Long.parseLong(getNextArgRequired());
             int amplitude = hasAmplitude ? Integer.parseInt(getNextArgRequired())
                     : VibrationEffect.DEFAULT_AMPLITUDE;
-            composition.addEffect(VibrationEffect.createOneShot(duration, amplitude), delay);
+            composition.addOffDuration(Duration.ofMillis(delay));
+            composition.addEffect(VibrationEffect.createOneShot(duration, amplitude));
         }
 
         private void addWaveformToComposition(VibrationEffect.Composition composition) {
@@ -1762,23 +1767,44 @@
                 }
             }
 
+            // Add delay before the waveform.
+            composition.addOffDuration(Duration.ofMillis(delay));
+
             VibrationEffect.WaveformBuilder waveform = VibrationEffect.startWaveform();
             for (int i = 0; i < durations.size(); i++) {
-                if (isContinuous) {
-                    if (hasFrequencies) {
-                        waveform.addRamp(amplitudes.get(i), frequencies.get(i), durations.get(i));
-                    } else {
-                        waveform.addRamp(amplitudes.get(i), durations.get(i));
-                    }
+                Duration transitionDuration = isContinuous
+                        ? Duration.ofMillis(durations.get(i))
+                        : Duration.ZERO;
+
+                if (hasFrequencies) {
+                    waveform.addTransition(transitionDuration, targetAmplitude(amplitudes.get(i)),
+                            targetFrequency(frequencies.get(i)));
                 } else {
+                    waveform.addTransition(transitionDuration, targetAmplitude(amplitudes.get(i)));
+                }
+                if (!isContinuous) {
+                    waveform.addSustain(Duration.ofMillis(durations.get(i)));
+                }
+
+                if ((i > 0) && (i == repeat)) {
+                    // Add segment that is not repeated to the composition and reset builder.
+                    composition.addEffect(waveform.build());
+
                     if (hasFrequencies) {
-                        waveform.addStep(amplitudes.get(i), frequencies.get(i), durations.get(i));
+                        waveform = VibrationEffect.startWaveform(targetAmplitude(amplitudes.get(i)),
+                                targetFrequency(frequencies.get(i)));
                     } else {
-                        waveform.addStep(amplitudes.get(i), durations.get(i));
+                        waveform = VibrationEffect.startWaveform(
+                                targetAmplitude(amplitudes.get(i)));
                     }
                 }
             }
-            composition.addEffect(waveform.build(repeat), delay);
+            if (repeat < 0) {
+                composition.addEffect(waveform.build());
+            } else {
+                // The waveform was already split at the repeat index, just repeat what remains.
+                composition.repeatEffectIndefinitely(waveform.build());
+            }
         }
 
         private void addPrebakedToComposition(VibrationEffect.Composition composition) {
@@ -1796,7 +1822,8 @@
             }
 
             int effectId = Integer.parseInt(getNextArgRequired());
-            composition.addEffect(VibrationEffect.get(effectId, shouldFallback), delay);
+            composition.addOffDuration(Duration.ofMillis(delay));
+            composition.addEffect(VibrationEffect.get(effectId, shouldFallback));
         }
 
         private void addPrimitivesToComposition(VibrationEffect.Composition composition) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 49d6a34..897549b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -395,9 +395,9 @@
     // How many activities have to be scheduled to stop to force a stop pass.
     private static final int MAX_STOPPING_TO_FORCE = 3;
 
-    private static final int STARTING_WINDOW_TYPE_NONE = 0;
-    private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
-    private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
+    static final int STARTING_WINDOW_TYPE_NONE = 0;
+    static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
+    static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
 
     static final int INVALID_PID = -1;
 
@@ -2149,7 +2149,8 @@
 
         final int typeParameter = StartingSurfaceController
                 .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
-                        allowTaskSnapshot, activityCreated, useEmpty, useLegacy, activityAllDrawn);
+                        allowTaskSnapshot, activityCreated, useEmpty, useLegacy, activityAllDrawn,
+                        type, packageName, mUserId);
 
         if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
             if (isActivityTypeHome()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e119a9a..5164bf0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2924,7 +2924,7 @@
         final boolean onTop =
                 (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
         return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, mSourceRootTask, onTop,
-                mLaunchParams, launchFlags, mRequest.realCallingPid, mRequest.realCallingUid);
+                mLaunchParams, launchFlags);
     }
 
     private boolean isLaunchModeOneOf(int mode1, int mode2) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index dd394ca..5d879ce 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2224,25 +2224,9 @@
             return;
         }
 
-        if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
-            if (task.mTransitionController.isShellTransitionsEnabled()) return;
-            // Dismiss docked root task. If task appeared to be in docked root task but is not
-            // resizable - we need to move it to top of fullscreen root task, otherwise it will
-            // be covered.
-            final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
-            if (taskDisplayArea.isSplitScreenModeActivated()) {
-                // Display a warning toast that we tried to put an app that doesn't support
-                // split-screen in split-screen.
-                mService.getTaskChangeNotificationController()
-                        .notifyActivityDismissingDockedRootTask();
-                taskDisplayArea.onSplitScreenModeDismissed(task);
-                taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
-                        true /* notifyClients */);
-            }
-            return;
+        if (!forceNonResizable) {
+            handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
         }
-
-        handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
     }
 
     /** Notifies that the top activity of the task is forced to be resizeable. */
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5facc0d..a1c823e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3043,13 +3043,6 @@
             mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
         }
         amendWindowTapExcludeRegion(mTouchExcludeRegion);
-        // TODO(multi-display): Support docked root tasks on secondary displays & task containers.
-        if (mDisplayId == DEFAULT_DISPLAY
-                && getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
-            mDividerControllerLocked.getTouchRegion(mTmpRect);
-            mTmpRegion.set(mTmpRect);
-            mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
-        }
         mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
     }
 
@@ -3440,12 +3433,6 @@
         if (rootPinnedTask != null) {
             pw.println(prefix + "rootPinnedTask=" + rootPinnedTask.getName());
         }
-        final Task rootSplitScreenPrimaryTask = getDefaultTaskDisplayArea()
-                .getRootSplitScreenPrimaryTask();
-        if (rootSplitScreenPrimaryTask != null) {
-            pw.println(
-                    prefix + "rootSplitScreenPrimaryTask=" + rootSplitScreenPrimaryTask.getName());
-        }
         // TODO: Support recents on non-default task containers
         final Task rootRecentsTask = getDefaultTaskDisplayArea().getRootTask(
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
@@ -4849,13 +4836,10 @@
         }
 
         private static boolean skipImeWindowsDuringTraversal(DisplayContent dc) {
-            // We skip IME windows so they're processed just above their target, except
-            // in split-screen mode where we process the IME containers above the docked divider.
+            // We skip IME windows so they're processed just above their target.
             // Note that this method check should align with {@link
             // WindowState#applyImeWindowsIfNeeded} in case of any state mismatch.
             return dc.mImeLayeringTarget != null
-                    && (!dc.getDefaultTaskDisplayArea().isSplitScreenModeActivated()
-                             || dc.mImeLayeringTarget.getTask() == null)
                     // Make sure that the IME window won't be skipped to report that it has
                     // completed the orientation change.
                     && !dc.mWmService.mDisplayFrozen;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index baf7f87..5c8502b 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -450,16 +450,6 @@
             return;
         }
 
-        // Dismiss split screen
-        // The lock screen is currently showing, but is occluded by a window that can
-        // show on top of the lock screen. In this can we want to dismiss the docked
-        // stack since it will be complicated/risky to try to put the activity on top
-        // of the lock screen in the right fullscreen configuration.
-        final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
-        if (taskDisplayArea.isSplitScreenModeActivated()) {
-            taskDisplayArea.onSplitScreenModeDismissed();
-        }
-
         // Dismiss freeform windowing mode
         if (currentTaskControllingOcclusion == null) {
             return;
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 3793e4b..8e5d73f 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -150,10 +150,8 @@
 
             if (mTmpParams.hasWindowingMode() && task.isRootTask()
                     && mTmpParams.mWindowingMode != task.getWindowingMode()) {
-                final int activityType = activity != null
-                        ? activity.getActivityType() : task.getActivityType();
                 task.setWindowingMode(task.getDisplayArea().validateWindowingMode(
-                        mTmpParams.mWindowingMode, activity, task, activityType));
+                        mTmpParams.mWindowingMode, activity, task));
             }
 
             if (mTmpParams.mBounds.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4c72d02b..76a7981 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1907,10 +1907,6 @@
         final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
         final int focusRootTaskId = topFocusedRootTask != null
                 ? topFocusedRootTask.getRootTaskId() : INVALID_TASK_ID;
-        // We dismiss the docked root task whenever we switch users.
-        if (getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
-            getDefaultTaskDisplayArea().onSplitScreenModeDismissed();
-        }
         // Also dismiss the pinned root task whenever we switch users. Removing the pinned root task
         // will also cause all tasks to be moved to the fullscreen root task at a position that is
         // appropriate.
@@ -2765,8 +2761,7 @@
     Task getLaunchRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
             @Nullable Task candidateTask, boolean onTop) {
         return getLaunchRootTask(r, options, candidateTask, null /* sourceTask */, onTop,
-                null /* launchParams */, 0 /* launchFlags */, -1 /* no realCallingPid */,
-                -1 /* no realCallingUid */);
+                null /* launchParams */, 0 /* launchFlags */);
     }
 
     /**
@@ -2785,8 +2780,7 @@
     Task getLaunchRootTask(@Nullable ActivityRecord r,
             @Nullable ActivityOptions options, @Nullable Task candidateTask,
             @Nullable Task sourceTask, boolean onTop,
-            @Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags,
-            int realCallingPid, int realCallingUid) {
+            @Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
         int taskId = INVALID_TASK_ID;
         int displayId = INVALID_DISPLAY;
         TaskDisplayArea taskDisplayArea = null;
@@ -2835,11 +2829,7 @@
 
         if (taskDisplayArea != null) {
             final int tdaDisplayId = taskDisplayArea.getDisplayId();
-            final boolean canLaunchOnDisplayFromStartRequest =
-                    realCallingPid != 0 && realCallingUid > 0 && r != null
-                            && mTaskSupervisor.canPlaceEntityOnDisplay(tdaDisplayId,
-                            realCallingPid, realCallingUid, r.info);
-            if (canLaunchOnDisplayFromStartRequest || canLaunchOnDisplay(r, tdaDisplayId)) {
+            if (canLaunchOnDisplay(r, tdaDisplayId)) {
                 if (r != null) {
                     final Task result = getValidLaunchRootTaskInTaskDisplayArea(
                             taskDisplayArea, r, candidateTask, options, launchParams);
@@ -2872,8 +2862,7 @@
             container = rootTask.getDisplayArea();
             if (container != null && canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
                 if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
-                    windowingMode = container.resolveWindowingMode(r, options, candidateTask,
-                            activityType);
+                    windowingMode = container.resolveWindowingMode(r, options, candidateTask);
                 }
                 // Always allow organized tasks that created by organizer since the activity type
                 // of an organized task is decided by the activity type of its top child, which
@@ -2889,8 +2878,7 @@
                 || !canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
             container = getDefaultTaskDisplayArea();
             if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
-                windowingMode = container.resolveWindowingMode(r, options, candidateTask,
-                        activityType);
+                windowingMode = container.resolveWindowingMode(r, options, candidateTask);
             }
         }
 
@@ -2952,8 +2940,7 @@
             windowingMode = options != null ? options.getLaunchWindowingMode()
                     : r.getWindowingMode();
         }
-        windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask,
-                r.getActivityType());
+        windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask);
 
         // Return the topmost valid root task on the display.
         final int targetWindowingMode = windowingMode;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 5276dc6..9b94f44 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -251,6 +251,11 @@
     }
 
     @Override
+    public void clearTouchableRegion(IWindow window) {
+        mService.clearTouchableRegion(this, window);
+    }
+
+    @Override
     public void finishDrawing(IWindow window,
             @Nullable SurfaceControl.Transaction postDrawTransaction) {
         if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 6ed59e9..2eab3ba 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -141,8 +141,7 @@
                 && mShellRootLayer != SHELL_ROOT_LAYER_PIP) {
             return null;
         }
-        if (mShellRootLayer == SHELL_ROOT_LAYER_DIVIDER
-                && !mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
+        if (mShellRootLayer == SHELL_ROOT_LAYER_DIVIDER) {
             return null;
         }
         if (mShellRootLayer == SHELL_ROOT_LAYER_PIP
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index eb73cd8..2a3767f 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -18,6 +18,7 @@
 
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
@@ -25,12 +26,17 @@
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN;
 
+import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.pm.ApplicationInfo;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.window.TaskSnapshot;
 
@@ -43,6 +49,14 @@
 public class StartingSurfaceController {
     private static final String TAG = TAG_WITH_CLASS_NAME
             ? StartingSurfaceController.class.getSimpleName() : TAG_WM;
+    /**
+     * Allow the empty style splash screen view can be copy and transfer to another process if
+     * the app targeting to {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU)
+    private static final long ALLOW_COPY_EMPTY_VIEW = 205907456L;
+
     private final WindowManagerService mService;
     private final SplashScreenExceptionList mSplashScreenExceptionsList;
 
@@ -81,7 +95,8 @@
 
     static int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
             boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated,
-            boolean useEmpty, boolean useLegacy, boolean activityDrawn) {
+            boolean useEmpty, boolean useLegacy, boolean activityDrawn, int startingWindowType,
+            String packageName, int userId) {
         int parameter = 0;
         if (newTask) {
             parameter |= TYPE_PARAMETER_NEW_TASK;
@@ -107,6 +122,11 @@
         if (activityDrawn) {
             parameter |= TYPE_PARAMETER_ACTIVITY_DRAWN;
         }
+        if (startingWindowType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
+                && CompatChanges.isChangeEnabled(ALLOW_COPY_EMPTY_VIEW, packageName,
+                UserHandle.of(userId))) {
+            parameter |= TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN;
+        }
         return parameter;
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ff9d9f7..91c1374 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4500,22 +4500,11 @@
         // right mode.
         if (!creating) {
             if (!taskDisplayArea.isValidWindowingMode(windowingMode, null /* ActivityRecord */,
-                    topTask, getActivityType())) {
+                    topTask)) {
                 windowingMode = WINDOWING_MODE_UNDEFINED;
             }
         }
 
-        final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated();
-
-        if (creating && alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
-                && isActivityTypeStandardOrUndefined()) {
-            // If the root task is being created explicitly in fullscreen mode, dismiss split-screen
-            // and display a warning toast about it.
-            mAtmService.getTaskChangeNotificationController()
-                    .notifyActivityDismissingDockedRootTask();
-            taskDisplayArea.onSplitScreenModeDismissed(this);
-        }
-
         if (currentMode == windowingMode) {
             // You are already in the window mode, so we can skip most of the work below. However,
             // it's possible that we have inherited the current windowing mode from a parent. So,
@@ -6501,9 +6490,8 @@
 
             if (!TaskDisplayArea.isWindowingModeSupported(mWindowingMode,
                     mAtmService.mSupportsMultiWindow,
-                    mAtmService.mSupportsSplitScreenMultiWindow,
                     mAtmService.mSupportsFreeformWindowManagement,
-                    mAtmService.mSupportsPictureInPicture, mActivityType)) {
+                    mAtmService.mSupportsPictureInPicture)) {
                 throw new IllegalArgumentException("Can't create root task for unsupported "
                         + "windowingMode=" + mWindowingMode);
             }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index dfb559f..1bba103 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -24,8 +24,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
@@ -53,8 +51,6 @@
 import android.util.Slog;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
@@ -114,7 +110,6 @@
     // through the list to find them.
     private Task mRootHomeTask;
     private Task mRootPinnedTask;
-    private Task mRootSplitScreenPrimaryTask;
 
     // TODO(b/159029784): Remove when getStack() behavior is cleaned-up
     private Task mRootRecentsTask;
@@ -232,8 +227,6 @@
         }
         if (windowingMode == WINDOWING_MODE_PINNED) {
             return mRootPinnedTask;
-        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            return mRootSplitScreenPrimaryTask;
         }
         return getRootTask(rootTask -> {
             if (activityType == ACTIVITY_TYPE_UNDEFINED
@@ -265,21 +258,6 @@
         return mRootPinnedTask;
     }
 
-    Task getRootSplitScreenPrimaryTask() {
-        return mRootSplitScreenPrimaryTask;
-    }
-
-    Task getRootSplitScreenSecondaryTask() {
-        // Only check the direct child Task for now, since the primary is also a direct child Task.
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task task = mChildren.get(i).asTask();
-            if (task != null && task.inSplitScreenSecondaryWindowingMode()) {
-                return task;
-            }
-        }
-        return null;
-    }
-
     ArrayList<Task> getVisibleTasks() {
         final ArrayList<Task> visibleTasks = new ArrayList<>();
         forAllTasks(task -> {
@@ -333,14 +311,6 @@
                                 + " already exist on display=" + this + " rootTask=" + rootTask);
             }
             mRootPinnedTask = rootTask;
-        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            if (mRootSplitScreenPrimaryTask != null) {
-                throw new IllegalArgumentException(
-                        "addRootTaskReferenceIfNeeded: root split screen primary task="
-                                + mRootSplitScreenPrimaryTask
-                                + " already exist on display=" + this + " rootTask=" + rootTask);
-            }
-            mRootSplitScreenPrimaryTask = rootTask;
         }
     }
 
@@ -351,8 +321,6 @@
             mRootRecentsTask = null;
         } else if (rootTask == mRootPinnedTask) {
             mRootPinnedTask = null;
-        } else if (rootTask == mRootSplitScreenPrimaryTask) {
-            mRootSplitScreenPrimaryTask = null;
         }
     }
 
@@ -708,39 +676,13 @@
             }, SCREEN_ORIENTATION_UNSET);
         }
 
-        if (isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
-            // Apps and their containers are not allowed to specify an orientation while using
-            // root tasks...except for the root home task if it is not resizable and currently
-            // visible (top of) its root task.
-            if (mRootHomeTask != null && !mRootHomeTask.isResizeable()) {
-                // Manually nest one-level because because getOrientation() checks fillsParent()
-                // which checks that requestedOverrideBounds() is empty. However, in this case,
-                // it is not empty because it's been overridden to maintain the fullscreen size
-                // within a smaller split-root.
-                final Task topHomeTask = mRootHomeTask.getTopMostTask();
-                final ActivityRecord topHomeActivity = topHomeTask.getTopNonFinishingActivity();
-                // If a home activity is in the process of launching and isn't yet visible we
-                // should still respect the root task's preferred orientation to ensure rotation
-                // occurs before the home activity finishes launching.
-                final boolean isHomeActivityLaunching = topHomeActivity != null
-                        && topHomeActivity.mVisibleRequested;
-                if (topHomeTask.isVisible() || isHomeActivityLaunching) {
-                    final int orientation = topHomeTask.getOrientation();
-                    if (orientation != SCREEN_ORIENTATION_UNSET) {
-                        return orientation;
-                    }
-                }
-            }
+        // Apps and their containers are not allowed to specify an orientation of non floating
+        // visible tasks created by organizer. The organizer handles the orientation instead.
+        final Task nonFloatingTopTask =
+                getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating());
+        if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer
+                && nonFloatingTopTask.isVisible()) {
             return SCREEN_ORIENTATION_UNSPECIFIED;
-        } else {
-            // Apps and their containers are not allowed to specify an orientation of non floating
-            // visible tasks created by organizer. The organizer handles the orientation instead.
-            final Task nonFloatingTopTask =
-                    getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating());
-            if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer
-                    && nonFloatingTopTask.isVisible()) {
-                return SCREEN_ORIENTATION_UNSPECIFIED;
-            }
         }
 
         final int orientation = super.getOrientation(candidate);
@@ -845,7 +787,7 @@
                     && child.inMultiWindowMode()
                     && childTask.getRootTask().getAdjacentTaskFragment() != null;
 
-            if (inAdjacentTask || child.inSplitScreenWindowingMode()) {
+            if (inAdjacentTask) {
                 hasAdjacentTask = true;
             } else if (hasAdjacentTask && startLayer < SPLIT_DIVIDER_LAYER) {
                 // Task on top of adjacent tasks should be higher than split divider layer so
@@ -1086,7 +1028,7 @@
         // Validate that our desired windowingMode will work under the current conditions.
         // UNDEFINED windowing mode is a valid result and means that the new root task will inherit
         // it's display's windowing mode.
-        windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
+        windowingMode = validateWindowingMode(windowingMode, r, candidateTask);
         return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask,
                 options, launchFlags);
     }
@@ -1283,23 +1225,6 @@
                 continue;
             }
 
-            if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                    && candidate == null && rootTask.inSplitScreenPrimaryWindowingMode()) {
-                // If the currently focused root task is in split-screen secondary we save off the
-                // top primary split-screen root task as a candidate for focus because we might
-                // prefer focus to move to an other root task to avoid primary split-screen root
-                // task overlapping with a fullscreen root task when a fullscreen root task is
-                // higher in z than the next split-screen root task. Assistant root task, I am
-                // looking at you...
-                // We only move the focus to the primary-split screen root task if there isn't a
-                // better alternative.
-                candidate = rootTask;
-                continue;
-            }
-            if (candidate != null && rootTask.inSplitScreenSecondaryWindowingMode()) {
-                // Use the candidate root task since we are now at the secondary split-screen.
-                return candidate;
-            }
             return rootTask;
         }
         return candidate;
@@ -1416,75 +1341,18 @@
         return someActivityPaused[0] > 0;
     }
 
-    void onSplitScreenModeDismissed() {
-        // The focused task could be a non-resizeable fullscreen root task that is on top of the
-        // other split-screen tasks, therefore had to dismiss split-screen, make sure the current
-        // focused root task can still be on top after dismissal
-        final Task rootTask = getFocusedRootTask();
-        final Task toTop =
-                rootTask != null && !rootTask.inSplitScreenWindowingMode() ? rootTask : null;
-        onSplitScreenModeDismissed(toTop);
-    }
-
-    void onSplitScreenModeDismissed(Task toTop) {
-        mAtmService.deferWindowLayout();
-        try {
-            moveSplitScreenTasksToFullScreen();
-        } finally {
-            final Task topFullscreenRootTask = toTop != null
-                    ? toTop : getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
-            final Task rootHomeTask = getOrCreateRootHomeTask();
-            if (rootHomeTask != null && ((topFullscreenRootTask != null && !isTopRootTask(
-                    rootHomeTask)) || toTop != null)) {
-                // Whenever split-screen is dismissed we want the root home task directly behind the
-                // current top fullscreen root task so it shows up when the top root task is
-                // finished. Or, if the caller specified a root task to be on top after
-                // split-screen is dismissed.
-                // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
-                // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
-                // once we have that.
-                rootHomeTask.moveToFront("onSplitScreenModeDismissed");
-                topFullscreenRootTask.moveToFront("onSplitScreenModeDismissed");
-            }
-            mAtmService.continueWindowLayout();
-        }
-    }
-
-    private void moveSplitScreenTasksToFullScreen() {
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
-        mTmpTasks.clear();
-        forAllTasks(task -> {
-            if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
-                mTmpTasks.add(task);
-            }
-        });
-
-        for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
-            final Task root = mTmpTasks.get(i);
-            for (int j = 0; j < root.getChildCount(); j++) {
-                final WindowContainerToken token =
-                        root.getChildAt(j).mRemoteToken.toWindowContainerToken();
-                wct.reparent(token, null, true /* toTop */);
-                wct.setBounds(token, null);
-            }
-        }
-        mAtmService.mWindowOrganizerController.applyTransaction(wct);
-    }
 
     /**
      * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
      *
      * @param windowingMode       The windowing mode we are checking support for.
      * @param supportsMultiWindow If we should consider support for multi-window mode in general.
-     * @param supportsSplitScreen If we should consider support for split-screen multi-window.
      * @param supportsFreeform    If we should consider support for freeform multi-window.
      * @param supportsPip         If we should consider support for picture-in-picture mutli-window.
-     * @param activityType        The activity type under consideration.
      * @return true if the windowing mode is supported.
      */
     static boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
-            boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
-            int activityType) {
+            boolean supportsFreeform, boolean supportsPip) {
 
         if (windowingMode == WINDOWING_MODE_UNDEFINED
                 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
@@ -1498,12 +1366,6 @@
             return true;
         }
 
-        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
-            return supportsSplitScreen
-                    && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
-        }
-
         if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
             return false;
         }
@@ -1525,7 +1387,7 @@
      * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
      */
     int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
-            @Nullable Task task, int activityType) {
+            @Nullable Task task) {
 
         // First preference if the windowing mode in the activity options if set.
         int windowingMode = (options != null)
@@ -1545,7 +1407,7 @@
                 windowingMode = getWindowingMode();
             }
         }
-        windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
+        windowingMode = validateWindowingMode(windowingMode, r, task);
         return windowingMode != WINDOWING_MODE_UNDEFINED
                 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
     }
@@ -1557,19 +1419,16 @@
      * @param windowingMode The windowing-mode to validate.
      * @param r             The {@link ActivityRecord} to check against.
      * @param task          The {@link Task} to check against.
-     * @param activityType  An activity type.
      * @return {@code true} if windowingMode is valid, {@code false} otherwise.
      */
-    boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
-            int activityType) {
+    boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task
+    ) {
         // Make sure the windowing mode we are trying to use makes sense for what is supported.
         boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
-        boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
         boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
         boolean supportsPip = mAtmService.mSupportsPictureInPicture;
         if (supportsMultiWindow) {
             if (task != null) {
-                supportsSplitScreen = task.supportsSplitScreenWindowingModeInDisplayArea(this);
                 supportsFreeform = task.supportsFreeformInDisplayArea(this);
                 supportsMultiWindow = task.supportsMultiWindowInDisplayArea(this)
                         // When the activity needs to be moved to PIP while the Task is not in PIP,
@@ -1577,7 +1436,6 @@
                         // always valid for Task as long as the device supports it.
                         || (windowingMode == WINDOWING_MODE_PINNED && supportsPip);
             } else if (r != null) {
-                supportsSplitScreen = r.supportsSplitScreenWindowingModeInDisplayArea(this);
                 supportsFreeform = r.supportsFreeformInDisplayArea(this);
                 supportsPip = r.supportsPictureInPicture();
                 supportsMultiWindow = r.supportsMultiWindowInDisplayArea(this);
@@ -1585,8 +1443,8 @@
         }
 
         return windowingMode != WINDOWING_MODE_UNDEFINED
-                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
-                supportsFreeform, supportsPip, activityType);
+                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsFreeform,
+                supportsPip);
     }
 
     /**
@@ -1596,20 +1454,10 @@
      * @param windowingMode The windowing-mode to validate.
      * @param r             The {@link ActivityRecord} to check against.
      * @param task          The {@link Task} to check against.
-     * @param activityType  An activity type.
      * @return The provided windowingMode or the closest valid mode which is appropriate.
      */
-    int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
-            int activityType) {
-        final boolean inSplitScreenMode = isSplitScreenModeActivated();
-        if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
-            // Switch to the display's windowing mode if we are not in split-screen mode and we are
-            // trying to launch in split-screen secondary.
-            windowingMode = WINDOWING_MODE_UNDEFINED;
-        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_UNDEFINED) {
-            windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-        }
-        if (!isValidWindowingMode(windowingMode, r, task, activityType)) {
+    int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task) {
+        if (!isValidWindowingMode(windowingMode, r, task)) {
             return WINDOWING_MODE_UNDEFINED;
         }
         return windowingMode;
@@ -1774,11 +1622,6 @@
         return homeTask;
     }
 
-    boolean isSplitScreenModeActivated() {
-        Task task = getRootSplitScreenPrimaryTask();
-        return task != null && task.hasChild();
-    }
-
     /**
      * Returns the topmost root task on the display that is compatible with the input windowing
      * mode. Null is no compatible root task on the display.
@@ -1866,8 +1709,7 @@
                 continue;
             }
             final int winMode = s.getWindowingMode();
-            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
-                    || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN;
             if (s.shouldBeVisible(null) && isValidWindowingMode) {
                 // Move the provided root task to behind this root task
                 final int position = Math.max(0, rootTaskNdx - 1);
@@ -1882,8 +1724,7 @@
     private Task getBottomMostVisibleRootTask(Task excludeRootTask) {
         return getRootTask(task -> {
             final int winMode = task.getWindowingMode();
-            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
-                    || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN;
             return task.shouldBeVisible(null) && isValidWindowingMode;
         }, false /* traverseTopToBottom */);
     }
@@ -2067,20 +1908,11 @@
             numRootTasks = mChildren.size();
         }
 
-        if (lastReparentedRootTask != null) {
-            if (toDisplayArea.isSplitScreenModeActivated()
-                    && !lastReparentedRootTask.supportsSplitScreenWindowingModeInDisplayArea(
-                            toDisplayArea)) {
-                // Dismiss split screen if the last reparented root task doesn't support split mode.
-                mAtmService.getTaskChangeNotificationController()
-                        .notifyActivityDismissingDockedRootTask();
-                toDisplayArea.onSplitScreenModeDismissed(lastReparentedRootTask);
-            } else if (!lastReparentedRootTask.isRootTask()) {
-                // Update focus when the last reparented root task is not a root task anymore.
-                // (For example, if it has been reparented to a split screen root task, move the
-                // focus to the split root task)
-                lastReparentedRootTask.getRootTask().moveToFront("display-removed");
-            }
+        if (lastReparentedRootTask != null && !lastReparentedRootTask.isRootTask()) {
+            // Update focus when the last reparented root task is not a root task anymore.
+            // (For example, if it has been reparented to a split screen root task, move the
+            // focus to the split root task)
+            lastReparentedRootTask.getRootTask().moveToFront("display-removed");
         }
 
         mRemoved = true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7b6e4bda..eb1274c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2105,6 +2105,19 @@
         Slog.i(tag, s, e);
     }
 
+    void clearTouchableRegion(Session session, IWindow client) {
+        int uid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                WindowState w = windowForClientLocked(session, client, false);
+                w.clearClientTouchableRegion();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
             Rect visibleInsets, Region touchableRegion) {
         int uid = Binder.getCallingUid();
@@ -2130,6 +2143,7 @@
                     }
                     w.setDisplayLayoutNeeded();
                     mWindowPlacerLocked.performSurfacePlacement();
+                    w.getDisplayContent().getInputMonitor().updateInputWindowsLw(true);
 
                     // We need to report touchable region changes to accessibility.
                     if (mAccessibilityController.hasCallbacks()) {
@@ -2608,6 +2622,10 @@
 
     void finishDrawingWindow(Session session, IWindow client,
             @Nullable SurfaceControl.Transaction postDrawTransaction) {
+        if (postDrawTransaction != null) {
+            postDrawTransaction.sanitize();
+        }
+
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 690928c..8864b98 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -652,6 +652,7 @@
 
     private final Rect mTmpRect = new Rect();
     private final Point mTmpPoint = new Point();
+    private final Region mTmpRegion = new Region();
 
     private final Transaction mTmpTransaction;
 
@@ -1730,20 +1731,6 @@
             } else {
                 intersectWithRootTaskBounds = false;
             }
-            if (inSplitScreenPrimaryWindowingMode()) {
-                // If this is in the primary split and the root home task is the top visible task in
-                // the secondary split, it means this is "minimized" and thus must prevent
-                // overlapping with home.
-                // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
-                final Task rootSecondary =
-                        task.getDisplayArea().getRootSplitScreenSecondaryTask();
-                if (rootSecondary.isActivityTypeHome() || rootSecondary.isActivityTypeRecents()) {
-                    final WindowContainer topTask = rootSecondary.getTopChild();
-                    if (topTask.isVisible()) {
-                        cutRect(mTmpRect, topTask.getBounds());
-                    }
-                }
-            }
         }
 
         bounds.set(mWindowFrames.mFrame);
@@ -2774,6 +2761,7 @@
                 region.set(-dw, -dh, dw + dw, dh + dh);
             }
             subtractTouchExcludeRegionIfNeeded(region);
+
         } else {
             // Not modal
             getTouchableRegion(region);
@@ -2784,6 +2772,14 @@
         if (frame.left != 0 || frame.top != 0) {
             region.translate(-frame.left, -frame.top);
         }
+        if (modal && mTouchableInsets == TOUCHABLE_INSETS_REGION) {
+            // The client gave us a touchable region and so first
+            // we calculate the untouchable region, then punch that out of our
+            // expanded modal region.
+            mTmpRegion.set(0, 0, frame.right, frame.bottom);
+            mTmpRegion.op(mGivenTouchableRegion, Region.Op.DIFFERENCE);
+            region.op(mTmpRegion, Region.Op.DIFFERENCE);
+        }
 
         // TODO(b/139804591): sizecompat layout needs to be reworked. Currently mFrame is post-
         // scaling but the existing logic doesn't expect that. The result is that the already-
@@ -4704,14 +4700,6 @@
         if (!isImeLayeringTarget()) {
             return false;
         }
-        // If we are in split screen which case we process the IME at the DisplayContent level to
-        // ensure it is above the docked divider.
-        // i.e. Like {@link DisplayContent.ImeContainer#skipImeWindowsDuringTraversal}, the IME
-        // window will be ignored to traverse when the IME target is still in split-screen mode.
-        if (mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()
-                && getTask() != null) {
-            return false;
-        }
         // Note that we don't process IME window if the IME input target is not on the screen.
         // In case some unexpected IME visibility cases happen like starting the remote
         // animation on the keyguard but seeing the IME window that originally on the app
@@ -6018,4 +6006,9 @@
         }
         mWmService.handleTaskFocusChange(getTask(), mActivityRecord);
     }
+
+    void clearClientTouchableRegion() {
+        mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+        mGivenTouchableRegion.setEmpty();
+    }
 }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 79a980f..95ef5f7 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -145,8 +145,8 @@
         "libutils",
         "libhwui",
         "libbpf_android",
-        "libnetdbpf",
         "libnetdutils",
+        "libnetworkstats",
         "libpsi",
         "libdataloader",
         "libincfs",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index f19202a..2090ab3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -32,6 +32,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.app.admin.PasswordPolicy;
+import android.app.admin.PreferentialNetworkServiceConfig;
 import android.graphics.Color;
 import android.os.Bundle;
 import android.os.PersistableBundle;
@@ -306,6 +307,8 @@
     public boolean mAdminCanGrantSensorsPermissions;
     public boolean mPreferentialNetworkServiceEnabled =
             DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
+    public PreferentialNetworkServiceConfig mPreferentialNetworkServiceConfig =
+            PreferentialNetworkServiceConfig.DEFAULT;
 
     private static final boolean USB_DATA_SIGNALING_ENABLED_DEFAULT = true;
     boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8a85fbb..733cfcd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -125,6 +125,7 @@
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -199,6 +200,7 @@
 import android.app.admin.ParcelableResource;
 import android.app.admin.PasswordMetrics;
 import android.app.admin.PasswordPolicy;
+import android.app.admin.PreferentialNetworkServiceConfig;
 import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.app.admin.StartInstallingUpdateCallback;
@@ -3362,14 +3364,14 @@
         updatePermissionPolicyCache(userId);
         updateAdminCanGrantSensorsPermissionCache(userId);
 
-        final boolean preferentialNetworkServiceEnabled;
+        final PreferentialNetworkServiceConfig preferentialNetworkServiceConfig;
         synchronized (getLockObject()) {
             ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
-            preferentialNetworkServiceEnabled = owner != null
-                    ? owner.mPreferentialNetworkServiceEnabled
-                             : DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
+            preferentialNetworkServiceConfig = owner != null
+                    ? owner.mPreferentialNetworkServiceConfig
+                    : PreferentialNetworkServiceConfig.DEFAULT;
         }
-        updateNetworkPreferenceForUser(userId, preferentialNetworkServiceEnabled);
+        updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfig);
 
         startOwnerService(userId, "start-user");
     }
@@ -3386,7 +3388,7 @@
 
     @Override
     void handleStopUser(int userId) {
-        updateNetworkPreferenceForUser(userId, false);
+        updateNetworkPreferenceForUser(userId, PreferentialNetworkServiceConfig.DEFAULT);
         stopOwnerService(userId, "stop-user");
     }
 
@@ -11040,7 +11042,8 @@
 
     @Override
     public int getLogoutUserId() {
-        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+        Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+                || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
 
         return getLogoutUserIdUnchecked();
     }
@@ -11055,16 +11058,7 @@
         }
     }
 
-    @Override
-    public void clearLogoutUser() {
-        CallerIdentity caller = getCallerIdentity();
-        Preconditions.checkCallAuthorization(canManageUsers(caller));
-
-        Slogf.i(LOG_TAG, "Clearing logout user as requested by %s", caller);
-        clearLogoutUserUnchecked();
-    }
-
-    private void clearLogoutUserUnchecked() {
+    private void clearLogoutUser() {
         if (!mInjector.userManagerIsHeadlessSystemUserMode()) return; // ignore
 
         synchronized (getLockObject()) {
@@ -11165,6 +11159,21 @@
             return stopUserUnchecked(callingUserId);
         }
 
+        return logoutUserUnchecked(/* userIdToStop= */ callingUserId);
+    }
+
+    @Override
+    public int logoutUserInternal() {
+        CallerIdentity caller = getCallerIdentity();
+        Preconditions.checkCallAuthorization(
+                canManageUsers(caller) || hasCallingOrSelfPermission(permission.CREATE_USERS));
+
+        int result = logoutUserUnchecked(getCurrentForegroundUserId());
+        Slogf.d(LOG_TAG, "logout called by uid %d. Result: %d", caller.getUid(), result);
+        return result;
+    }
+
+    private int logoutUserUnchecked(@UserIdInt int userIdToStop) {
         int logoutUserId = getLogoutUserIdUnchecked();
         if (logoutUserId == UserHandle.USER_NULL) {
             // Could happen on devices using headless system user mode when called before calling
@@ -11180,7 +11189,7 @@
                 // This should never happen as target user is determined by getPreviousUserId()
                 return UserManager.USER_OPERATION_ERROR_UNKNOWN;
             }
-            clearLogoutUserUnchecked();
+            clearLogoutUser();
         } catch (RemoteException e) {
             // Same process, should not happen.
             return UserManager.USER_OPERATION_ERROR_UNKNOWN;
@@ -11188,7 +11197,7 @@
             mInjector.binderRestoreCallingIdentity(id);
         }
 
-        return stopUserUnchecked(callingUserId);
+        return stopUserUnchecked(userIdToStop);
     }
 
     private int stopUserUnchecked(@UserIdInt int userId) {
@@ -12168,7 +12177,7 @@
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(isProfileOwner(caller),
                 "Caller is not profile owner;"
-                        + " only profile owner may control the preferntial network service");
+                        + " only profile owner may control the preferential network service");
         synchronized (getLockObject()) {
             final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
                     caller.getUserId());
@@ -12205,6 +12214,47 @@
     }
 
     @Override
+    public void setPreferentialNetworkServiceConfig(
+            PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
+        if (!mHasFeature) {
+            return;
+        }
+        final CallerIdentity caller = getCallerIdentity();
+        Preconditions.checkCallAuthorization(isProfileOwner(caller),
+                "Caller is not profile owner;"
+                        + " only profile owner may control the preferential network service");
+        synchronized (getLockObject()) {
+            final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
+                    caller.getUserId());
+            if (!requiredAdmin.mPreferentialNetworkServiceConfig.equals(
+                    preferentialNetworkServiceConfig)) {
+                requiredAdmin.mPreferentialNetworkServiceConfig = preferentialNetworkServiceConfig;
+                saveSettingsLocked(caller.getUserId());
+            }
+        }
+        updateNetworkPreferenceForUser(caller.getUserId(), preferentialNetworkServiceConfig);
+        DevicePolicyEventLogger
+                .createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED)
+                .setBoolean(preferentialNetworkServiceConfig.isEnabled())
+                .write();
+    }
+
+    @Override
+    public PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() {
+        if (!mHasFeature) {
+            return PreferentialNetworkServiceConfig.DEFAULT;
+        }
+
+        final CallerIdentity caller = getCallerIdentity();
+        Preconditions.checkCallAuthorization(isProfileOwner(caller),
+                "Caller is not profile owner");
+        synchronized (getLockObject()) {
+            final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(caller.getUserId());
+            return requiredAdmin.mPreferentialNetworkServiceConfig;
+        }
+    }
+
+    @Override
     public void setLockTaskPackages(ComponentName who, String[] packages)
             throws SecurityException {
         Objects.requireNonNull(who, "ComponentName is null");
@@ -18027,8 +18077,6 @@
         if (!isManagedProfile(userId)) {
             return;
         }
-        int networkPreference = preferentialNetworkServiceEnabled
-                ? PROFILE_NETWORK_PREFERENCE_ENTERPRISE : PROFILE_NETWORK_PREFERENCE_DEFAULT;
         ProfileNetworkPreference.Builder preferenceBuilder =
                 new ProfileNetworkPreference.Builder();
         if (preferentialNetworkServiceEnabled) {
@@ -18045,6 +18093,40 @@
                         null /* executor */, null /* listener */));
     }
 
+    private void updateNetworkPreferenceForUser(int userId,
+            PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
+        if (!isManagedProfile(userId)) {
+            return;
+        }
+        ProfileNetworkPreference.Builder preferenceBuilder =
+                new ProfileNetworkPreference.Builder();
+        if (preferentialNetworkServiceConfig.isEnabled()) {
+            if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) {
+                preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+            } else {
+                preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+            }
+        } else {
+            preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
+        }
+        List<Integer> allowedUids = Arrays.stream(
+                preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
+                        Collectors.toList());
+        List<Integer> excludedUids = Arrays.stream(
+                preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
+                Collectors.toList());
+        preferenceBuilder.setIncludedUids(allowedUids);
+        preferenceBuilder.setExcludedUids(excludedUids);
+        preferenceBuilder.setPreferenceEnterpriseId(
+                preferentialNetworkServiceConfig.getNetworkId());
+        List<ProfileNetworkPreference> preferences = new ArrayList<>();
+        preferences.add(preferenceBuilder.build());
+        mInjector.binderWithCleanCallingIdentity(() ->
+                mInjector.getConnectivityManager().setProfileNetworkPreferences(
+                        UserHandle.of(userId), preferences,
+                        null /* executor */, null /* listener */));
+    }
+
     @Override
     public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
         if (!mHasFeature) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index bdfa3bf..d5e4710 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -18,6 +18,8 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+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.app.GameServiceProviderInstanceImplTest.FakeGameService.GameServiceState;
 
 import static com.google.common.collect.Iterables.getOnlyElement;
@@ -28,16 +30,19 @@
 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 static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
+import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.app.ITaskStackListener;
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -57,6 +62,7 @@
 import android.view.SurfaceControlViewHost.SurfacePackage;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.infra.AndroidFuture;
@@ -99,6 +105,10 @@
     private static final ComponentName GAME_A_MAIN_ACTIVITY =
             new ComponentName(GAME_A_PACKAGE, "com.package.game.a.MainActivity");
 
+    private static final String GAME_B_PACKAGE = "com.package.game.b";
+    private static final ComponentName GAME_B_MAIN_ACTIVITY =
+            new ComponentName(GAME_B_PACKAGE, "com.package.game.b.MainActivity");
+
     private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
 
     private MockitoSession mMockingSession;
@@ -109,6 +119,9 @@
     private WindowManagerService mMockWindowManagerService;
     @Mock
     private WindowManagerInternal mMockWindowManagerInternal;
+    @Mock
+    private IActivityManager mMockActivityManager;
+    private FakeContext mFakeContext;
     private FakeGameClassifier mFakeGameClassifier;
     private FakeGameService mFakeGameService;
     private FakeServiceConnector<IGameService> mFakeGameServiceConnector;
@@ -117,6 +130,9 @@
     private ArrayList<ITaskStackListener> mTaskStackListeners;
     private ArrayList<RunningTaskInfo> mRunningTaskInfos;
 
+    @Mock
+    private PackageManager mMockPackageManager;
+
     @Before
     public void setUp() throws PackageManager.NameNotFoundException, RemoteException {
         mMockingSession = mockitoSession()
@@ -124,8 +140,11 @@
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
+        mFakeContext = new FakeContext(InstrumentationRegistry.getInstrumentation().getContext());
+
         mFakeGameClassifier = new FakeGameClassifier();
         mFakeGameClassifier.recordGamePackage(GAME_A_PACKAGE);
+        mFakeGameClassifier.recordGamePackage(GAME_B_PACKAGE);
 
         mFakeGameService = new FakeGameService();
         mFakeGameServiceConnector = new FakeServiceConnector<>(mFakeGameService);
@@ -150,7 +169,9 @@
         mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
                 new UserHandle(USER_ID),
                 ConcurrentUtils.DIRECT_EXECUTOR,
+                mFakeContext,
                 mFakeGameClassifier,
+                mMockActivityManager,
                 mMockActivityTaskManager,
                 mMockWindowManagerService,
                 mMockWindowManagerInternal,
@@ -660,6 +681,58 @@
         assertEquals(TEST_BITMAP, result.getBitmap());
     }
 
+    @Test
+    public void restartGame_taskIdAssociatedWithGame_restartsTargetGame() throws Exception {
+        Intent launchIntent = new Intent("com.test.ACTION_LAUNCH_GAME_PACKAGE")
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        when(mMockPackageManager.getLaunchIntentForPackage(GAME_A_PACKAGE))
+                .thenReturn(launchIntent);
+
+        mGameServiceProviderInstance.start();
+
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+        startTask(11, GAME_B_MAIN_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(11);
+
+        FakeGameSession gameSession11 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(11)
+                .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+        mFakeGameSessionService.getCapturedCreateInvocations().get(0)
+                .mGameSessionController.restartGame(10);
+
+        verify(mMockActivityManager).forceStopPackage(GAME_A_PACKAGE, UserHandle.USER_CURRENT);
+        assertThat(mFakeContext.getLastStartedIntent()).isEqualTo(launchIntent);
+    }
+
+    @Test
+    public void restartGame_taskIdNotAssociatedWithGame_noOp() throws Exception {
+        mGameServiceProviderInstance.start();
+
+        startTask(10, GAME_A_MAIN_ACTIVITY);
+        mFakeGameService.requestCreateGameSession(10);
+
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+        getOnlyElement(
+                mFakeGameSessionService.getCapturedCreateInvocations())
+                .mGameSessionController.restartGame(11);
+
+        verifyZeroInteractions(mMockActivityManager);
+        assertThat(mFakeContext.getLastStartedIntent()).isNull();
+    }
+
     private void startTask(int taskId, ComponentName componentName) {
         RunningTaskInfo runningTaskInfo = new RunningTaskInfo();
         runningTaskInfo.taskId = taskId;
@@ -826,4 +899,32 @@
             mIsFocused = focused;
         }
     }
-}
\ No newline at end of file
+
+    private final class FakeContext extends ContextWrapper {
+        private Intent mLastStartedIntent;
+
+        FakeContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return mMockPackageManager;
+        }
+
+        @Override
+        public void startActivity(Intent intent) {
+            mLastStartedIntent = intent;
+        }
+
+        @Override
+        public void enforceCallingPermission(String permission, @Nullable String message) {
+            // Do nothing.
+        }
+
+        Intent getLastStartedIntent() {
+            return mLastStartedIntent;
+        }
+    }
+
+}
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 677f0f6..36c37c4 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -541,14 +541,11 @@
                     | ActivityManager.UID_OBSERVER_CAPABILITY
         };
         final IUidObserver[] observers = new IUidObserver.Stub[changesToObserve.length];
-        doReturn(Process.myUid()).when(sPackageManagerInternal)
-                .getPackageUid(mContext.getOpPackageName(), 0 /* flags */, mContext.getUserId());
         for (int i = 0; i < observers.length; ++i) {
             observers[i] = mock(IUidObserver.Stub.class);
             when(observers[i].asBinder()).thenReturn((IBinder) observers[i]);
             mAms.registerUidObserver(observers[i], changesToObserve[i] /* which */,
-                    ActivityManager.PROCESS_STATE_UNKNOWN /* cutpoint */,
-                    mContext.getOpPackageName());
+                    ActivityManager.PROCESS_STATE_UNKNOWN /* cutpoint */, null /* caller */);
 
             // When we invoke AMS.registerUidObserver, there are some interactions with observers[i]
             // mock in RemoteCallbackList class. We don't want to test those interactions and
@@ -677,12 +674,10 @@
         mockNoteOperation();
 
         final IUidObserver observer = mock(IUidObserver.Stub.class);
+
         when(observer.asBinder()).thenReturn((IBinder) observer);
-        doReturn(Process.myUid()).when(sPackageManagerInternal)
-                .getPackageUid(mContext.getOpPackageName(), 0 /* flags */, mContext.getUserId());
         mAms.registerUidObserver(observer, ActivityManager.UID_OBSERVER_PROCSTATE /* which */,
-                ActivityManager.PROCESS_STATE_SERVICE /* cutpoint */,
-                mContext.getOpPackageName());
+                ActivityManager.PROCESS_STATE_SERVICE /* cutpoint */, null /* callingPackage */);
         // When we invoke AMS.registerUidObserver, there are some interactions with observer
         // mock in RemoteCallbackList class. We don't want to test those interactions and
         // at the same time, we don't want those to interfere with verifyNoMoreInteractions.
@@ -776,9 +771,7 @@
 
         final IUidObserver observer = mock(IUidObserver.Stub.class);
         when(observer.asBinder()).thenReturn((IBinder) observer);
-        doReturn(Process.myUid()).when(sPackageManagerInternal)
-                .getPackageUid(mContext.getOpPackageName(), 0 /* flags */, mContext.getUserId());
-        mAms.registerUidObserver(observer, 0, 0, mContext.getOpPackageName());
+        mAms.registerUidObserver(observer, 0, 0, null);
         // Verify that when observers are registered, then validateUids is correctly updated.
         addPendingUidChanges(pendingItemsForUids);
         mAms.mUidObserverController.dispatchUidsChanged();
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 6818d1f..49635a9 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -33,6 +33,7 @@
 import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG;
 import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG;
 import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG;
+import static com.android.server.am.UserController.USER_COMPLETED_EVENT_MSG;
 import static com.android.server.am.UserController.USER_CURRENT_MSG;
 import static com.android.server.am.UserController.USER_START_MSG;
 import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
@@ -45,6 +46,7 @@
 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.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
@@ -91,6 +93,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.FgThread;
+import com.android.server.SystemService;
 import com.android.server.am.UserState.KeyEvictedCallback;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerService;
@@ -167,6 +170,8 @@
             doReturn(false).when(mInjector).taskSupervisorSwitchUser(anyInt(), any());
             doNothing().when(mInjector).taskSupervisorResumeFocusedStackTopActivity();
             doNothing().when(mInjector).systemServiceManagerOnUserStopped(anyInt());
+            doNothing().when(mInjector).systemServiceManagerOnUserCompletedEvent(
+                    anyInt(), anyInt());
             doNothing().when(mInjector).activityManagerForceStopPackage(anyInt(), anyString());
             doNothing().when(mInjector).activityManagerOnUserStopped(anyInt());
             doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
@@ -719,6 +724,54 @@
         }
     }
 
+    @Test
+    public void testScheduleOnUserCompletedEvent() throws Exception {
+        // user1 is starting, switching, and unlocked, but not scheduled unlocked yet
+        // user2 is starting and had unlocked but isn't unlocked anymore for whatever reason
+
+        final int user1 = 101;
+        final int user2 = 102;
+        setUpUser(user1, 0);
+        setUpUser(user2, 0);
+
+        mUserController.startUser(user1, /* foreground= */ true);
+        mUserController.getStartedUserState(user1).setState(UserState.STATE_RUNNING_UNLOCKED);
+
+        mUserController.startUser(user2, /* foreground= */ false);
+        mUserController.getStartedUserState(user2).setState(UserState.STATE_RUNNING_LOCKED);
+
+        final int event1a = SystemService.UserCompletedEventType.EVENT_TYPE_USER_STARTING;
+        final int event1b = SystemService.UserCompletedEventType.EVENT_TYPE_USER_SWITCHING;
+
+        final int event2a = SystemService.UserCompletedEventType.EVENT_TYPE_USER_STARTING;
+        final int event2b = SystemService.UserCompletedEventType.EVENT_TYPE_USER_UNLOCKED;
+
+
+        mUserController.scheduleOnUserCompletedEvent(user1, event1a, 2000);
+        assertNotNull(mInjector.mHandler.getMessageForCode(USER_COMPLETED_EVENT_MSG, user1));
+        assertNull(mInjector.mHandler.getMessageForCode(USER_COMPLETED_EVENT_MSG, user2));
+
+        mUserController.scheduleOnUserCompletedEvent(user2, event2a, 2000);
+        assertNotNull(mInjector.mHandler.getMessageForCode(USER_COMPLETED_EVENT_MSG, user1));
+        assertNotNull(mInjector.mHandler.getMessageForCode(USER_COMPLETED_EVENT_MSG, user2));
+
+        mUserController.scheduleOnUserCompletedEvent(user2, event2b, 2000);
+        mUserController.scheduleOnUserCompletedEvent(user1, event1b, 2000);
+        mUserController.scheduleOnUserCompletedEvent(user1, 0, 2000);
+
+        assertNotNull(mInjector.mHandler.getMessageForCode(USER_COMPLETED_EVENT_MSG, user1));
+        assertNotNull(mInjector.mHandler.getMessageForCode(USER_COMPLETED_EVENT_MSG, user2));
+
+        mUserController.reportOnUserCompletedEvent(user1);
+        verify(mInjector, times(1))
+                .systemServiceManagerOnUserCompletedEvent(eq(user1), eq(event1a | event1b));
+        verify(mInjector, never()).systemServiceManagerOnUserCompletedEvent(eq(user2), anyInt());
+
+        mUserController.reportOnUserCompletedEvent(user2);
+        verify(mInjector, times(1))
+                .systemServiceManagerOnUserCompletedEvent(eq(user2), eq(event2a));
+    }
+
     private void setUpAndStartUserInBackground(int userId) throws Exception {
         setUpUser(userId, 0);
         mUserController.startUser(userId, /* foreground= */ false);
@@ -969,8 +1022,12 @@
         }
 
         Message getMessageForCode(int what) {
+            return getMessageForCode(what, null);
+        }
+
+        Message getMessageForCode(int what, Object obj) {
             for (Message msg : mMessages) {
-                if (msg.what == what) {
+                if (msg.what == what && (obj == null || obj.equals(msg.obj))) {
                     return msg;
                 }
             }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 72100e44..e36263e 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -18,17 +18,21 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+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.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
 
 import android.Manifest;
 import android.app.admin.DevicePolicyManager;
+import android.companion.AssociationInfo;
 import android.companion.virtual.IVirtualDeviceActivityListener;
 import android.companion.virtual.VirtualDeviceParams;
 import android.content.Context;
@@ -41,24 +45,35 @@
 import android.hardware.input.VirtualMouseRelativeEvent;
 import android.hardware.input.VirtualMouseScrollEvent;
 import android.hardware.input.VirtualTouchEvent;
+import android.net.MacAddress;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.IThermalService;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.WorkSource;
 import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 import android.view.KeyEvent;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
 
 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;
 
 @Presubmit
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class VirtualDeviceManagerServiceTest {
 
     private static final String DEVICE_NAME = "device name";
@@ -84,6 +99,11 @@
     private InputManagerInternal mInputManagerInternalMock;
     @Mock
     private IVirtualDeviceActivityListener mActivityListener;
+    @Mock
+    IPowerManager mIPowerManagerMock;
+    @Mock
+    IThermalService mIThermalServiceMock;
+    private PowerManager mPowerManager;
 
     @Before
     public void setUp() {
@@ -102,10 +122,17 @@
         when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
                 mDevicePolicyManagerMock);
 
+        mPowerManager = new PowerManager(mContext, mIPowerManagerMock, mIThermalServiceMock,
+                new Handler(TestableLooper.get(this).getLooper()));
+        when(mContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager);
+
         mInputController = new InputController(new Object(), mNativeWrapperMock);
+        AssociationInfo associationInfo = new AssociationInfo(1, 0, null,
+                MacAddress.BROADCAST_ADDRESS, "", null, true, false, 0, 0);
         mDeviceImpl = new VirtualDeviceImpl(mContext,
-                /* association info */ null, new Binder(), /* uid */ 0, mInputController,
-                (int associationId) -> {}, mPendingTrampolineCallback, mActivityListener,
+                associationInfo, new Binder(), /* uid */ 0, mInputController,
+                (int associationId) -> {
+                }, mPendingTrampolineCallback, mActivityListener,
                 new VirtualDeviceParams.Builder().build());
     }
 
@@ -118,6 +145,72 @@
     }
 
     @Test
+    public void onVirtualDisplayCreatedLocked_wakeLockIsAcquired() throws RemoteException {
+        final int displayId = 2;
+        mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+        verify(mIPowerManagerMock, never()).acquireWakeLock(any(Binder.class), anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), anyInt());
+        TestableLooper.get(this).processAllMessages();
+        verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), eq(displayId));
+    }
+
+    @Test
+    public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
+            throws RemoteException {
+        final int displayId = 2;
+        mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+        assertThrows(IllegalStateException.class,
+                () -> mDeviceImpl.onVirtualDisplayCreatedLocked(displayId));
+        TestableLooper.get(this).processAllMessages();
+        verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(any(Binder.class), anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), eq(displayId));
+    }
+
+    @Test
+    public void onVirtualDisplayRemovedLocked_unknownDisplayId_throwsException() {
+        final int unknownDisplayId = 999;
+        assertThrows(IllegalStateException.class,
+                () -> mDeviceImpl.onVirtualDisplayRemovedLocked(unknownDisplayId));
+    }
+
+    @Test
+    public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
+        final int displayId = 2;
+        mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+        ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
+        TestableLooper.get(this).processAllMessages();
+        verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
+                anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), eq(displayId));
+
+        IBinder wakeLock = wakeLockCaptor.getValue();
+        mDeviceImpl.onVirtualDisplayRemovedLocked(displayId);
+        verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt());
+    }
+
+    @Test
+    public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
+        final int displayId = 2;
+        mDeviceImpl.onVirtualDisplayCreatedLocked(displayId);
+        ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
+        TestableLooper.get(this).processAllMessages();
+        verify(mIPowerManagerMock, Mockito.times(1)).acquireWakeLock(wakeLockCaptor.capture(),
+                anyInt(),
+                nullable(String.class), nullable(String.class), nullable(WorkSource.class),
+                nullable(String.class), eq(displayId));
+        IBinder wakeLock = wakeLockCaptor.getValue();
+
+        // Close the VirtualDevice without first notifying it of the VirtualDisplay removal.
+        mDeviceImpl.close();
+        verify(mIPowerManagerMock, Mockito.times(1)).releaseWakeLock(eq(wakeLock), anyInt());
+    }
+
+    @Test
     public void createVirtualKeyboard_noDisplay_failsSecurityException() {
         assertThrows(
                 SecurityException.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 63dfc85..c0ad69f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -42,6 +42,7 @@
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
 import static android.net.InetAddresses.parseNumericAddress;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 
@@ -94,6 +95,7 @@
 import android.app.admin.DevicePolicyManagerLiteInternal;
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.app.admin.PasswordMetrics;
+import android.app.admin.PreferentialNetworkServiceConfig;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.admin.WifiSsidPolicy;
 import android.content.BroadcastReceiver;
@@ -4146,6 +4148,164 @@
     }
 
     @Test
+    public void testSetPreferentialNetworkServiceConfig_noProfileOwner() throws Exception {
+        assertExpectException(SecurityException.class, null,
+                () -> dpm.setPreferentialNetworkServiceConfig(
+                        PreferentialNetworkServiceConfig.DEFAULT));
+    }
+
+    @Test
+    public void testIsPreferentialNetworkServiceEnabled_noProfileOwner() throws Exception {
+        assertExpectException(SecurityException.class, null,
+                () -> dpm.isPreferentialNetworkServiceEnabled());
+    }
+
+    @Test
+    public void testSetPreferentialNetworkServiceConfig_invalidConfig() throws Exception {
+        final int managedProfileUserId = 15;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        mContext.binder.callingUid = managedProfileAdminUid;
+
+        PreferentialNetworkServiceConfig.Builder preferentialNetworkServiceConfigBuilder =
+                new PreferentialNetworkServiceConfig.Builder();
+        assertExpectException(NullPointerException.class, null,
+                () -> preferentialNetworkServiceConfigBuilder.setIncludedUids(null));
+        assertExpectException(NullPointerException.class, null,
+                () -> preferentialNetworkServiceConfigBuilder.setExcludedUids(null));
+        assertExpectException(IllegalArgumentException.class, null,
+                () -> preferentialNetworkServiceConfigBuilder.setNetworkId(6));
+        int[] includedUids = new int[]{1, 2};
+        int[] excludedUids = new int[]{3, 4};
+        preferentialNetworkServiceConfigBuilder.setIncludedUids(includedUids);
+        preferentialNetworkServiceConfigBuilder.setExcludedUids(excludedUids);
+
+        assertExpectException(IllegalStateException.class, null,
+                () -> preferentialNetworkServiceConfigBuilder.build());
+    }
+
+    @Test
+    public void testSetPreferentialNetworkServiceConfig_defaultPreference() throws Exception {
+        final int managedProfileUserId = 15;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        mContext.binder.callingUid = managedProfileAdminUid;
+
+        dpm.setPreferentialNetworkServiceConfig(PreferentialNetworkServiceConfig.DEFAULT);
+        assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
+        assertThat(dpm.getPreferentialNetworkServiceConfig()
+                .isEnabled()).isFalse();
+
+        ProfileNetworkPreference preferenceDetails =
+                new ProfileNetworkPreference.Builder()
+                        .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+                        .build();
+        List<ProfileNetworkPreference> preferences = new ArrayList<>();
+        preferences.add(preferenceDetails);
+        verify(getServices().connectivityManager, times(1))
+                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+                        null, null);
+    }
+
+    @Test
+    public void testSetPreferentialNetworkServiceConfig_enterprisePreference() throws Exception {
+        PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
+                (new PreferentialNetworkServiceConfig.Builder())
+                        .setEnabled(true)
+                        .setNetworkId(NET_ENTERPRISE_ID_1)
+                        .build();
+
+        final int managedProfileUserId = 15;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        mContext.binder.callingUid = managedProfileAdminUid;
+
+        dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
+        assertThat(dpm.getPreferentialNetworkServiceConfig()
+                .isEnabled()).isTrue();
+        ProfileNetworkPreference preferenceDetails =
+                new ProfileNetworkPreference.Builder()
+                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE)
+                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
+                        .build();
+        List<ProfileNetworkPreference> preferences = new ArrayList<>();
+        preferences.add(preferenceDetails);
+        verify(getServices().connectivityManager, times(1))
+                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+                        null, null);
+    }
+
+    @Test
+    public void testSetPreferentialNetworkServiceConfig_enterprisePreferenceIncludedUids()
+            throws Exception {
+        final int managedProfileUserId = 15;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        mContext.binder.callingUid = managedProfileAdminUid;
+
+        PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
+                (new PreferentialNetworkServiceConfig.Builder())
+                        .setEnabled(true)
+                        .setNetworkId(NET_ENTERPRISE_ID_1)
+                        .setFallbackToDefaultConnectionAllowed(false)
+                        .setIncludedUids(new int[]{1, 2})
+                        .build();
+        dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
+        assertThat(dpm.getPreferentialNetworkServiceConfig()
+                .isEnabled()).isTrue();
+        List<Integer> includedList = new ArrayList<>();
+        includedList.add(1);
+        includedList.add(2);
+        ProfileNetworkPreference preferenceDetails =
+                new ProfileNetworkPreference.Builder()
+                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
+                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
+                        .setIncludedUids(includedList)
+                        .build();
+        List<ProfileNetworkPreference> preferences = new ArrayList<>();
+        preferences.add(preferenceDetails);
+        verify(getServices().connectivityManager, times(1))
+                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+                        null, null);
+    }
+
+    @Test
+    public void testSetPreferentialNetworkServiceConfig_enterprisePreferenceExcludedUids()
+            throws Exception {
+        final int managedProfileUserId = 15;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        mContext.binder.callingUid = managedProfileAdminUid;
+
+        PreferentialNetworkServiceConfig preferentialNetworkServiceConfigEnabled =
+                (new PreferentialNetworkServiceConfig.Builder())
+                        .setEnabled(true)
+                        .setNetworkId(NET_ENTERPRISE_ID_1)
+                        .setFallbackToDefaultConnectionAllowed(false)
+                        .setExcludedUids(new int[]{1, 2})
+                        .build();
+
+        dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
+        assertThat(dpm.getPreferentialNetworkServiceConfig()
+                .isEnabled()).isTrue();
+        List<Integer> excludedUids = new ArrayList<>();
+        excludedUids.add(1);
+        excludedUids.add(2);
+        ProfileNetworkPreference preferenceDetails =
+                new ProfileNetworkPreference.Builder()
+                        .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
+                        .setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
+                        .setExcludedUids(excludedUids)
+                        .build();
+        List<ProfileNetworkPreference> preferences = new ArrayList<>();
+        preferences.clear();
+        preferences.add(preferenceDetails);
+        verify(getServices().connectivityManager, times(1))
+                .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+                        null, null);
+    }
+
+    @Test
     public void testSetSystemSettingFailWithNonWhitelistedSettings() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index c675726..24a4751 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -393,7 +393,8 @@
 
         // Create an idle mode bms
         // This will fail if it tries to fetch the wrong configuration.
-        BrightnessMappingStrategy bms = BrightnessMappingStrategy.createForIdleMode(res, ddc);
+        BrightnessMappingStrategy bms = BrightnessMappingStrategy.createForIdleMode(res, ddc,
+                null);
         assertNotNull("BrightnessMappingStrategy should not be null", bms);
 
         // Ensure that the config is the one we set
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 eaa271a..1fb5898 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.PropertyInvalidatedCache;
+import android.companion.virtual.IVirtualDevice;
 import android.compat.testing.PlatformCompatChangeRule;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -73,6 +74,7 @@
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.display.DisplayManagerService.SyncRoot;
 import com.android.server.lights.LightsManager;
 import com.android.server.sensors.SensorManagerInternal;
@@ -167,6 +169,7 @@
             };
 
     @Mock InputManagerInternal mMockInputManagerInternal;
+    @Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
     @Mock IVirtualDisplayCallback.Stub mMockAppToken;
     @Mock IVirtualDisplayCallback.Stub mMockAppToken2;
     @Mock WindowManagerInternal mMockWindowManagerInternal;
@@ -187,6 +190,9 @@
         LocalServices.addService(LightsManager.class, mMockLightsManager);
         LocalServices.removeServiceForTest(SensorManagerInternal.class);
         LocalServices.addService(SensorManagerInternal.class, mMockSensorManagerInternal);
+        LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
+        LocalServices.addService(
+                VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal);
 
         mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         mDeviceConfig = new FakeDeviceConfigInterface();
@@ -661,6 +667,101 @@
     }
 
     /**
+     * Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is allowed when the permission
+     * ADD_TRUSTED_DISPLAY is granted.
+     */
+    @Test
+    public void testOwnDisplayGroup_allowCreationWithAddTrustedDisplayPermission() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, 600, 800, 320);
+        builder.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP);
+        builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
+
+        int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
+                null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+        displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
+        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+        assertNotNull(ddi);
+        assertNotEquals(0, ddi.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+    }
+
+    /**
+     * Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is blocked when the permission
+     * ADD_TRUSTED_DISPLAY is denied.
+     */
+    @Test
+    public void testOwnDisplayGroup_withoutAddTrustedDisplayPermission_throwsSecurityException() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, 600, 800, 320);
+        builder.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP);
+        builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
+
+        try {
+            bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
+                    null /* projection */, null /* virtualDeviceToken */, PACKAGE_NAME);
+            fail("Creating virtual display with VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP without "
+                    + "ADD_TRUSTED_DISPLAY permission should throw SecurityException.");
+        } catch (SecurityException e) {
+            // SecurityException is expected
+        }
+    }
+
+    /**
+     * Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is allowed when called with
+     * a virtual device, even if ADD_TRUSTED_DISPLAY is not granted.
+     */
+    @Test
+    public void testOwnDisplayGroup_allowCreationWithVirtualDevice() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, 600, 800, 320);
+        builder.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP);
+        builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
+
+        IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
+        when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
+            .thenReturn(true);
+
+        int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
+                null /* projection */, virtualDevice /* virtualDeviceToken */, PACKAGE_NAME);
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+        displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
+        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+        assertNotNull(ddi);
+        assertNotEquals(0, ddi.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+    }
+
+    /**
      * Tests that there is a display change notification if the frame rate override
      * list is updated.
      */
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
index 2565ae3..0f3742f 100644
--- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
@@ -37,7 +38,9 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.R;
+import com.android.server.LocalServices;
 import com.android.server.display.TestUtils;
+import com.android.server.display.color.ColorDisplayService;
 import com.android.server.display.utils.AmbientFilter;
 import com.android.server.display.utils.AmbientFilterStubber;
 
@@ -75,6 +78,7 @@
     @Mock private TypedArray mHighLightBiases;
     @Mock private TypedArray mAmbientColorTemperatures;
     @Mock private TypedArray mDisplayColorTemperatures;
+    @Mock private ColorDisplayService.ColorDisplayServiceInternal mColorDisplayServiceInternalMock;
 
     @Before
     public void setUp() throws Exception {
@@ -120,6 +124,18 @@
                 R.array.config_displayWhiteBalanceHighLightAmbientBiases))
                 .thenReturn(mHighLightBiases);
         mockThrottler();
+        LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
+        LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
+                mColorDisplayServiceInternalMock);
+    }
+
+    @Test
+    public void testCalculateAdjustedBrightnessNits() {
+        doReturn(0.9f).when(mColorDisplayServiceInternalMock).getDisplayWhiteBalanceLuminance();
+        DisplayWhiteBalanceController controller =
+                DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+        final float adjustedNits = controller.calculateAdjustedBrightnessNits(500f);
+        assertEquals(/* expected= */ 550f, adjustedNits, /* delta= */ 0.001);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java b/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java
new file mode 100644
index 0000000..c59b58d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.os.PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_TIMEOUT;
+import static android.os.PowerManager.WAKE_REASON_GESTURE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.power.PowerGroup}.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:PowerManagerServiceTest
+ */
+public class PowerGroupTest {
+
+    private static final int GROUP_ID = 0;
+    private static final long TIMESTAMP_CREATE = 1;
+    private static final long TIMESTAMP1 = 999;
+    private static final long TIMESTAMP2 = TIMESTAMP1 + 10;
+    private static final long TIMESTAMP3 = TIMESTAMP2 + 10;
+    private static final int UID = 11;
+
+    private PowerGroup mPowerGroup;
+    @Mock
+    private PowerGroup.PowerGroupListener mWakefulnessCallbackMock;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mPowerGroup = new PowerGroup(GROUP_ID, mWakefulnessCallbackMock, new DisplayPowerRequest(),
+                WAKEFULNESS_AWAKE, /* ready= */ true, /* supportsSandman= */true, TIMESTAMP_CREATE);
+    }
+
+    @Test
+    public void testDreamPowerGroupTriggersOnWakefulnessChangedCallback() {
+        mPowerGroup.dreamLocked(TIMESTAMP1, UID);
+        verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+                eq(WAKEFULNESS_DREAMING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_APPLICATION),
+                eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), /* details= */
+                isNull());
+    }
+
+    @Test
+    public void testLastWakeAndSleepTimeIsUpdated() {
+        assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+        assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+
+        // Verify that the transition to WAKEFULNESS_DOZING updates the last sleep time
+        String details = "PowerGroup1 Timeout";
+        mPowerGroup.setWakefulnessLocked(WAKEFULNESS_DOZING, TIMESTAMP1, UID,
+                GO_TO_SLEEP_REASON_TIMEOUT, /* opUid= */ 0, /* opPackageName= */ null, details);
+        assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP1);
+        assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+        assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+                eq(WAKEFULNESS_DOZING), eq(TIMESTAMP1), eq(GO_TO_SLEEP_REASON_TIMEOUT),
+                eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), eq(details));
+
+        // Verify that the transition to WAKEFULNESS_ASLEEP after dozing does not update the last
+        // wake or sleep time
+        mPowerGroup.setWakefulnessLocked(WAKEFULNESS_ASLEEP, TIMESTAMP2, UID,
+                GO_TO_SLEEP_REASON_DEVICE_ADMIN, /* opUid= */ 0, /* opPackageName= */ null,
+                details);
+        assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP1);
+        assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP_CREATE);
+        assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+                eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP2), eq(GO_TO_SLEEP_REASON_DEVICE_ADMIN),
+                eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), eq(details));
+
+        // Verify that waking up the power group only updates the last wake time
+        details = "PowerGroup1 Gesture";
+        mPowerGroup.setWakefulnessLocked(WAKEFULNESS_AWAKE, TIMESTAMP2, UID,
+                WAKE_REASON_GESTURE, /* opUid= */ 0, /* opPackageName= */ null, details);
+        assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP2);
+        assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP1);
+        assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+                eq(WAKEFULNESS_AWAKE), eq(TIMESTAMP2), eq(WAKE_REASON_GESTURE),
+                eq(UID), /* opUid= */ anyInt(), /* opPackageName= */ isNull(), eq(details));
+
+        // Verify that a transition to WAKEFULNESS_ASLEEP from an interactive state updates the last
+        // sleep time
+        mPowerGroup.setWakefulnessLocked(WAKEFULNESS_ASLEEP, TIMESTAMP3, UID,
+                GO_TO_SLEEP_REASON_DEVICE_ADMIN, /* opUid= */ 0, /* opPackageName= */ null,
+                details);
+        assertThat(mPowerGroup.getLastSleepTimeLocked()).isEqualTo(TIMESTAMP3);
+        assertThat(mPowerGroup.getLastWakeTimeLocked()).isEqualTo(TIMESTAMP2);
+        assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        verify(mWakefulnessCallbackMock).onWakefulnessChangedLocked(eq(GROUP_ID),
+                eq(WAKEFULNESS_ASLEEP), eq(TIMESTAMP3), eq(GO_TO_SLEEP_REASON_DEVICE_ADMIN),
+                eq(UID), /* opUid= */anyInt(), /* opPackageName= */ isNull(), eq(details));
+    }
+}
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 c832a3e..d35c679 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -111,6 +111,7 @@
  * Build/Install/Run:
  *  atest FrameworksServicesTests:PowerManagerServiceTest
  */
+@SuppressWarnings("GuardedBy")
 public class PowerManagerServiceTest {
     private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
     private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
@@ -437,7 +438,7 @@
     @Test
     public void testWakefulnessAwake_InitialValue() {
         createService();
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
@@ -445,12 +446,12 @@
         createService();
         // Start with AWAKE state
         startSystem();
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         // Take a nap and verify.
         mService.getBinderServiceInstance().goToSleep(mClock.now(),
                 PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
     }
 
     @Test
@@ -467,21 +468,21 @@
         int flags = PowerManager.FULL_WAKE_LOCK;
         mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
                 null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
 
         // Ensure that the flag does *NOT* work with a partial wake lock.
         flags = PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
         mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
                 null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
 
         // Verify that flag forces a wakeup when paired to a FULL_WAKE_LOCK
         flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
         mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
                 null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
     }
 
@@ -492,7 +493,7 @@
         forceSleep();
         mService.getBinderServiceInstance().wakeUp(mClock.now(),
                 PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     /**
@@ -511,7 +512,7 @@
                 .thenReturn(false);
         mService.readConfigurationLocked();
         setPluggedIn(true);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
                 .thenReturn(true);
         mService.readConfigurationLocked();
@@ -526,20 +527,20 @@
         when(mWirelessChargerDetectorMock.update(true /* isPowered */,
                 BatteryManager.BATTERY_PLUGGED_WIRELESS)).thenReturn(false);
         setPluggedIn(true);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
 
         // Test 3:
         // Do not wake up if the phone is being REMOVED from a wireless charger
         when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
         setPluggedIn(false);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
 
         // Test 4:
         // Do not wake if we are dreaming.
         forceAwake();  // Needs to be awake first before it can dream.
         forceDream();
         setPluggedIn(true);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
         forceSleep();
 
         // Test 5:
@@ -552,7 +553,7 @@
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug))
                 .thenReturn(false);
         setPluggedIn(false);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         Settings.Global.putInt(
                 mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0);
         mUserSwitchedReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_USER_SWITCHED));
@@ -565,14 +566,14 @@
         forceAwake();
         forceDozing();
         setPluggedIn(true);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
 
         // Test 7:
         // Finally, take away all the factors above and ensure the device wakes up!
         forceAwake();
         forceSleep();
         setPluggedIn(false);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
@@ -580,12 +581,12 @@
         createService();
         // Start with AWAKE state
         startSystem();
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         // Take a nap and verify.
         mService.getBinderServiceInstance().goToSleep(mClock.now(),
                 PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
     }
 
     @Test
@@ -616,12 +617,12 @@
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
         // Verify that we start awake
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         // Grab the wakefulness value when PowerManager finally calls into the
         // native component to actually perform the suspend.
         when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> {
-            assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+            assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
             return true;
         });
 
@@ -629,7 +630,7 @@
         assertThat(retval).isTrue();
 
         // Still asleep when the function returns.
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
     }
 
     @Test
@@ -662,7 +663,7 @@
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
         // Verify that we start awake
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         // Create a wakelock
         mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg,
@@ -718,7 +719,7 @@
 
         // Start with AWAKE state
         startSystem();
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         assertTrue(isAcquired[0]);
 
         // Take a nap and verify we no longer hold the blocker
@@ -728,7 +729,7 @@
         when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
         mService.getBinderServiceInstance().goToSleep(mClock.now(),
                 PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
         assertFalse(isAcquired[0]);
 
         // Override the display state by DreamManager and verify is reacquires the blocker.
@@ -841,9 +842,9 @@
         verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).show();
         when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
         advanceTime(70);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         forceAwake();
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).dismiss(false);
     }
 
@@ -862,7 +863,7 @@
         createService();
         startSystem();
         advanceTime(20);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
                 PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
     }
@@ -882,9 +883,9 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
                 null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY);
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         advanceTime(60);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
                 PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
     }
@@ -912,7 +913,7 @@
         mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
 
         advanceTime(520);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
                 PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
     }
@@ -934,7 +935,7 @@
                 PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS);
 
         advanceTime(520);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
                 PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE);
     }
@@ -955,7 +956,7 @@
                 PowerManager.USER_ACTIVITY_EVENT_OTHER, 0 /* flags */);
 
         advanceTime(520);
-        assertThat(mService.getWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_ASLEEP);
     }
 
     @Test
@@ -984,14 +985,14 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
                 null /* workSource */, null /* historyTag */, Display.DEFAULT_DISPLAY);
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
                 WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
                 WAKEFULNESS_AWAKE);
 
         advanceTime(15000);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
                 WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
@@ -1024,14 +1025,14 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
                 null /* workSource */, null /* historyTag */, Display.INVALID_DISPLAY);
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
                 WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
                 WAKEFULNESS_AWAKE);
 
         advanceTime(15000);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
                 WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
@@ -1069,14 +1070,14 @@
                 WAKEFULNESS_AWAKE);
         assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
                 WAKEFULNESS_AWAKE);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
 
         advanceTime(15000);
         assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
                 WAKEFULNESS_DOZING);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
     }
 
     @Test
@@ -1084,7 +1085,7 @@
         createService();
         startSystem();
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         verify(mNotifierMock, never()).onWakefulnessChangeStarted(anyInt(), anyInt(), anyLong());
     }
 
@@ -1103,7 +1104,7 @@
         createService();
         startSystem();
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
         verify(mNotifierMock).onWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP), anyInt(),
                 anyLong());
     }
@@ -1137,7 +1138,7 @@
                 PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
 
         mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
         assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
                 DisplayPowerRequest.POLICY_BRIGHT);
     }
@@ -1418,23 +1419,23 @@
         startSystem();
         listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
                 null, null);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
                 null, null);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
 
         mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
                 null, null);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
-    public void testMultiDisplay_addDisplayGroup_preservesWakefulness() {
+    public void testMultiDisplay_addDisplayGroup_wakesDeviceUp() {
         final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
         final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
                 new AtomicReference<>();
@@ -1446,15 +1447,15 @@
         createService();
         startSystem();
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
                 null, null);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
 
         listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
     }
 
     @Test
@@ -1471,18 +1472,79 @@
         startSystem();
         listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
 
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
                 null, null);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
 
         listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
 
         mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
                 null, null);
-        assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+    }
+
+    @Test
+    public void testMultiDisplay_updatesLastGlobalWakeTime() {
+        final int nonDefaultPowerGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+        final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+                new AtomicReference<>();
+        long eventTime1 = 10;
+        long eventTime2 = eventTime1 + 1;
+        long eventTime3 = eventTime2 + 1;
+        long eventTime4 = eventTime3 + 1;
+        doAnswer((Answer<Void>) invocation -> {
+            listener.set(invocation.getArgument(0));
+            return null;
+        }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+        createService();
+        startSystem();
+        listener.get().onDisplayGroupAdded(nonDefaultPowerGroupId);
+
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+        mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_DOZING, eventTime1,
+                0, PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, 0, null, null);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+        mService.setWakefulnessLocked(nonDefaultPowerGroupId, WAKEFULNESS_DOZING, eventTime2,
+                0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        assertThat(mService.getBinderServiceInstance().getLastSleepReason()).isEqualTo(
+                PowerManager.GO_TO_SLEEP_REASON_APPLICATION);
+
+        mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE,
+                eventTime3, /* uid= */ 0, PowerManager.WAKE_REASON_PLUGGED_IN, /* opUid= */
+                0, /* opPackageName= */ null, /* details= */ null);
+        PowerManager.WakeData wakeData = mService.getLocalServiceInstance().getLastWakeup();
+        assertThat(wakeData.wakeTime).isEqualTo(eventTime3);
+        assertThat(wakeData.wakeReason).isEqualTo(PowerManager.WAKE_REASON_PLUGGED_IN);
+        assertThat(wakeData.sleepDuration).isEqualTo(eventTime3 - eventTime2);
+
+        // The global wake time and reason as well as sleep duration shouldn't change when another
+        // PowerGroup wakes up.
+        mService.setWakefulnessLocked(nonDefaultPowerGroupId, WAKEFULNESS_AWAKE,
+                eventTime4, /* uid= */ 0, PowerManager.WAKE_REASON_CAMERA_LAUNCH, /* opUid= */
+                0, /* opPackageName= */ null, /* details= */ null);
+        assertThat(wakeData.wakeTime).isEqualTo(eventTime3);
+        assertThat(wakeData.wakeReason).isEqualTo(PowerManager.WAKE_REASON_PLUGGED_IN);
+        assertThat(wakeData.sleepDuration).isEqualTo(eventTime3 - eventTime2);
+    }
+
+    @Test
+    public void testLastSleepTime_notUpdatedWhenDreaming() {
+        createService();
+        startSystem();
+
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        PowerManager.WakeData initialWakeData = mService.getLocalServiceInstance().getLastWakeup();
+
+        forceDream();
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+        assertThat(mService.getLocalServiceInstance().getLastWakeup()).isEqualTo(initialWakeData);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 5dd44ff..020d9f8 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.vibrator;
 
+import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
+import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -69,6 +72,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.time.Duration;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -525,7 +529,8 @@
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
                 .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
-                .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK), /* delay= */ 100)
+                .addOffDuration(Duration.ofMillis(100))
+                .addEffect(VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .compose();
         VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
         waitForCompletion(thread);
@@ -558,11 +563,12 @@
                 0.5f /* 100Hz*/, 1 /* 150Hz */, 0.6f /* 200Hz */);
 
         long vibrationId = 1;
-        VibrationEffect effect = VibrationEffect.startWaveform()
-                .addStep(1, 10)
-                .addRamp(0, 20)
-                .addStep(0.8f, 100, 30)
-                .addRamp(0.6f, 200, 40)
+        VibrationEffect effect = VibrationEffect.startWaveform(targetAmplitude(1))
+                .addSustain(Duration.ofMillis(10))
+                .addTransition(Duration.ofMillis(20), targetAmplitude(0))
+                .addTransition(Duration.ZERO, targetAmplitude(0.8f), targetFrequency(100))
+                .addSustain(Duration.ofMillis(30))
+                .addTransition(Duration.ofMillis(40), targetAmplitude(0.6f), targetFrequency(200))
                 .build();
         VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
         waitForCompletion(thread);
@@ -595,11 +601,12 @@
         fakeVibrator.setPwleSizeMax(2);
 
         long vibrationId = 1;
-        VibrationEffect effect = VibrationEffect.startWaveform()
-                .addStep(1, 10)
-                .addRamp(0, 20)
-                .addStep(0.8f, 10, 30)
-                .addRamp(0.6f, 100, 40)
+        VibrationEffect effect = VibrationEffect.startWaveform(targetAmplitude(1))
+                .addSustain(Duration.ofMillis(10))
+                .addTransition(Duration.ofMillis(20), targetAmplitude(0))
+                .addTransition(Duration.ZERO, targetAmplitude(0.8f), targetFrequency(100))
+                .addSustain(Duration.ofMillis(30))
+                .addTransition(Duration.ofMillis(40), targetAmplitude(0.6f), targetFrequency(200))
                 .build();
         VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
         waitForCompletion(thread);
@@ -1261,7 +1268,9 @@
         fakeVibrator.setPwleSizeMax(2);
 
         long vibrationId = 1;
-        VibrationEffect effect = VibrationEffect.startWaveform().addRamp(1, 1).build();
+        VibrationEffect effect = VibrationEffect.startWaveform()
+                .addTransition(Duration.ofMillis(1), targetAmplitude(1))
+                .build();
         VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
         waitForCompletion(thread);
 
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 fdc8982..c58bf3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -340,7 +340,7 @@
             doReturn(stack).when(mRootWindowContainer)
                     .getLaunchRootTask(any(), any(), any(), anyBoolean());
             doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(), any(),
-                    anyBoolean(), any(), anyInt(), anyInt(), anyInt());
+                    anyBoolean(), any(), anyInt());
         }
 
         // Set up mock package manager internal and make sure no unmocked methods are called
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
similarity index 89%
rename from services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
rename to services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
index d64bf12..670eb75 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
@@ -31,7 +31,6 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
@@ -48,8 +47,7 @@
 import android.view.WindowManagerGlobal;
 import android.window.WindowTokenClient;
 
-import com.android.server.inputmethod.InputMethodManagerService;
-import com.android.server.inputmethod.InputMethodMenuController;
+import com.android.server.inputmethod.InputMethodDialogWindowContext;
 
 import org.junit.After;
 import org.junit.Before;
@@ -61,13 +59,13 @@
 //  scenario there.
 /**
  * Build/Install/Run:
- *  atest WmTests:InputMethodMenuControllerTest
+ *  atest WmTests:InputMethodDialogWindowContextTest
  */
 @Presubmit
 @RunWith(WindowTestRunner.class)
-public class InputMethodMenuControllerTest extends WindowTestsBase {
+public class InputMethodDialogWindowContextTest extends WindowTestsBase {
 
-    private InputMethodMenuController mController;
+    private InputMethodDialogWindowContext mWindowContext;
     private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay;
 
     private IWindowManager mIWindowManager;
@@ -80,7 +78,7 @@
                 new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider();
         Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
 
-        mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
+        mWindowContext = new InputMethodDialogWindowContext();
         mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
                 .Builder(mAtm, 1000, 1000).build();
         mSecondaryDisplay.getDisplayInfo().state = STATE_ON;
@@ -119,21 +117,21 @@
 
     @Test
     public void testGetSettingsContext() {
-        final Context contextOnDefaultDisplay = mController.getSettingsContext(DEFAULT_DISPLAY);
+        final Context contextOnDefaultDisplay = mWindowContext.get(DEFAULT_DISPLAY);
 
         assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay);
 
         // Obtain the context again and check if the window metrics match the IME container bounds
         // of the secondary display.
-        final Context contextOnSecondaryDisplay = mController.getSettingsContext(
-                mSecondaryDisplay.getDisplayId());
+        final Context contextOnSecondaryDisplay =
+                mWindowContext.get(mSecondaryDisplay.getDisplayId());
 
         assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay);
     }
 
     @Test
     public void testGetSettingsContextOnDualDisplayContent() {
-        final Context context = mController.getSettingsContext(mSecondaryDisplay.getDisplayId());
+        final Context context = mWindowContext.get(mSecondaryDisplay.getDisplayId());
         final WindowTokenClient tokenClient = (WindowTokenClient) context.getWindowContextToken();
         assertNotNull(tokenClient);
         spyOn(tokenClient);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index f4abf88..ee17f52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -25,7 +25,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.TYPE_VIRTUAL;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -935,39 +934,6 @@
         assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
     }
 
-    /**
-     * Test that {@link RootWindowContainer#getLaunchRootTask} with the real caller id will get the
-     * expected root task when requesting the activity launch on the secondary display.
-     */
-    @Test
-    public void testGetLaunchRootTaskWithRealCallerId() {
-        // Create a non-system owned virtual display.
-        final TestDisplayContent secondaryDisplay =
-                new TestDisplayContent.Builder(mAtm, 1000, 1500)
-                        .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
-
-        // Create an activity with specify the original launch pid / uid.
-        final ActivityRecord r = new ActivityBuilder(mAtm).setLaunchedFromPid(200)
-                .setLaunchedFromUid(200).build();
-
-        // Simulate ActivityStarter to find a launch root task for requesting the activity to launch
-        // on the secondary display with realCallerId.
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
-        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
-                300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
-        final Task result = mRootWindowContainer.getLaunchRootTask(r, options,
-                null /* task */, null /* sourceTask */, true /* onTop */, null /* launchParams */,
-                0 /* launchFlags */, 300 /* test realCallerPid */,
-                300 /* test realCallerUid */);
-
-        // Assert that the root task is returned as expected.
-        assertNotNull(result);
-        assertEquals("The display ID of the root task should same as secondary display ",
-                secondaryDisplay.mDisplayId, result.getDisplayId());
-    }
-
     @Test
     public void testGetValidLaunchRootTaskOnDisplayWithCandidateRootTask() {
         // Create a root task with an activity on secondary display.
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 85b1de5..9d4db00 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -41,7 +41,6 @@
 
     private final boolean mIsInputHeadset;
     private final boolean mIsOutputHeadset;
-    private final boolean mIsDock;
 
     private boolean mSelected = false;
     private int mOutputState;
@@ -54,7 +53,7 @@
 
     public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
             boolean hasOutput, boolean hasInput,
-            boolean isInputHeadset, boolean isOutputHeadset, boolean isDock) {
+            boolean isInputHeadset, boolean isOutputHeadset) {
         mAudioService = audioService;
         mCardNum = card;
         mDeviceNum = device;
@@ -63,32 +62,31 @@
         mHasInput = hasInput;
         mIsInputHeadset = isInputHeadset;
         mIsOutputHeadset = isOutputHeadset;
-        mIsDock = isDock;
     }
 
     /**
-     * @return the ALSA card number associated with this peripheral.
+     * @returns the ALSA card number associated with this peripheral.
      */
     public int getCardNum() {
         return mCardNum;
     }
 
     /**
-     * @return the ALSA device number associated with this peripheral.
+     * @returns the ALSA device number associated with this peripheral.
      */
     public int getDeviceNum() {
         return mDeviceNum;
     }
 
     /**
-     * @return the USB device device address associated with this peripheral.
+     * @returns the USB device device address associated with this peripheral.
      */
     public String getDeviceAddress() {
         return mDeviceAddress;
     }
 
     /**
-     * @return the ALSA card/device address string.
+     * @returns the ALSA card/device address string.
      */
     public String getAlsaCardDeviceString() {
         if (mCardNum < 0 || mDeviceNum < 0) {
@@ -100,42 +98,35 @@
     }
 
     /**
-     * @return true if the device supports output.
+     * @returns true if the device supports output.
      */
     public boolean hasOutput() {
         return mHasOutput;
     }
 
     /**
-     * @return true if the device supports input (recording).
+     * @returns true if the device supports input (recording).
      */
     public boolean hasInput() {
         return mHasInput;
     }
 
     /**
-     * @return true if the device is a headset for purposes of input.
+     * @returns true if the device is a headset for purposes of input.
      */
     public boolean isInputHeadset() {
         return mIsInputHeadset;
     }
 
     /**
-     * @return true if the device is a headset for purposes of output.
+     * @returns true if the device is a headset for purposes of output.
      */
     public boolean isOutputHeadset() {
         return mIsOutputHeadset;
     }
 
     /**
-     * @return true if the device is a USB dock.
-     */
-    public boolean isDock() {
-        return mIsDock;
-    }
-
-    /**
-     * @return true if input jack is detected or jack detection is not supported.
+     * @returns true if input jack is detected or jack detection is not supported.
      */
     private synchronized boolean isInputJackConnected() {
         if (mJackDetector == null) {
@@ -145,7 +136,7 @@
     }
 
     /**
-     * @return true if input jack is detected or jack detection is not supported.
+     * @returns true if input jack is detected or jack detection is not supported.
      */
     private synchronized boolean isOutputJackConnected() {
         if (mJackDetector == null) {
@@ -199,10 +190,9 @@
         try {
             // Output Device
             if (mHasOutput) {
-                int device = mIsDock ? AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET
-                        : (mIsOutputHeadset
-                            ? AudioSystem.DEVICE_OUT_USB_HEADSET
-                            : AudioSystem.DEVICE_OUT_USB_DEVICE);
+                int device = mIsOutputHeadset
+                        ? AudioSystem.DEVICE_OUT_USB_HEADSET
+                        : AudioSystem.DEVICE_OUT_USB_DEVICE;
                 if (DEBUG) {
                     Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device)
                             + " addr:" + alsaCardDeviceString
@@ -241,7 +231,7 @@
 
     /**
      * @Override
-     * @return a string representation of the object.
+     * @returns a string representation of the object.
      */
     public synchronized String toString() {
         return "UsbAlsaDevice: [card: " + mCardNum
@@ -283,7 +273,7 @@
 
     /**
      * @Override
-     * @return true if the objects are equivalent.
+     * @returns true if the objects are equivalent.
      */
     public boolean equals(Object obj) {
         if (!(obj instanceof UsbAlsaDevice)) {
@@ -295,13 +285,12 @@
                 && mHasOutput == other.mHasOutput
                 && mHasInput == other.mHasInput
                 && mIsInputHeadset == other.mIsInputHeadset
-                && mIsOutputHeadset == other.mIsOutputHeadset
-                && mIsDock == other.mIsDock);
+                && mIsOutputHeadset == other.mIsOutputHeadset);
     }
 
     /**
      * @Override
-     * @return a hash code generated from the object contents.
+     * @returns a hash code generated from the object contents.
      */
     public int hashCode() {
         final int prime = 31;
@@ -312,7 +301,6 @@
         result = prime * result + (mHasInput ? 0 : 1);
         result = prime * result + (mIsInputHeadset ? 0 : 1);
         result = prime * result + (mIsOutputHeadset ? 0 : 1);
-        result = prime * result + (mIsDock ? 0 : 1);
 
         return result;
     }
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index fd9b995..1c72eb8 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -237,7 +237,6 @@
         if (hasInput || hasOutput) {
             boolean isInputHeadset = parser.isInputHeadset();
             boolean isOutputHeadset = parser.isOutputHeadset();
-            boolean isDock = parser.isDock();
 
             if (mAudioService == null) {
                 Slog.e(TAG, "no AudioService");
@@ -247,7 +246,7 @@
             UsbAlsaDevice alsaDevice =
                     new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
                                       deviceAddress, hasOutput, hasInput,
-                                      isInputHeadset, isOutputHeadset, isDock);
+                                      isInputHeadset, isOutputHeadset);
             if (alsaDevice != null) {
                 alsaDevice.setDeviceNameAndDescription(
                           cardRec.getCardName(), cardRec.getCardDescription());
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 94cc826..9ac270f 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -165,7 +165,7 @@
                 pw.println("manfacturer:0x" + Integer.toHexString(deviceDescriptor.getVendorID())
                         + " product:" + Integer.toHexString(deviceDescriptor.getProductID()));
                 pw.println("isHeadset[in: " + parser.isInputHeadset()
-                        + " , out: " + parser.isOutputHeadset() + "], isDock: " + parser.isDock());
+                        + " , out: " + parser.isOutputHeadset() + "]");
             } else {
                 pw.println(formatTime() + " Disconnect " + mDeviceAddress);
             }
@@ -179,8 +179,9 @@
                 UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
                 descriptorTree.parse(parser);
                 descriptorTree.report(new TextReportCanvas(parser, stringBuilder));
+
                 stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
-                        + " , out: " + parser.isOutputHeadset() + "], isDock: " + parser.isDock());
+                        + " , out: " + parser.isOutputHeadset() + "]");
                 pw.println(stringBuilder.toString());
             } else {
                 pw.println(formatTime() + " Disconnect " + mDeviceAddress);
@@ -197,8 +198,9 @@
                     descriptor.report(canvas);
                 }
                 pw.println(stringBuilder.toString());
+
                 pw.println("isHeadset[in: " + parser.isInputHeadset()
-                        + " , out: " + parser.isOutputHeadset() + "], isDock: " + parser.isDock());
+                        + " , out: " + parser.isOutputHeadset() + "]");
             } else {
                 pw.println(formatTime() + " Disconnect " + mDeviceAddress);
             }
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 65b79bf..d0825ba 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -503,6 +503,49 @@
             return HAL_MODE_DFP;
     }
 
+    /**
+     * Reset USB port.
+     *
+     * @param portId port identifier.
+     */
+    public boolean resetUsbPort(@NonNull String portId, int transactionId,
+            @NonNull IUsbOperationInternal callback, IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            Objects.requireNonNull(callback);
+            Objects.requireNonNull(portId);
+            final PortInfo portInfo = mPorts.get(portId);
+            if (portInfo == null) {
+                logAndPrint(Log.ERROR, pw, "resetUsbPort: No such port: " + portId
+                    + " opId:" + transactionId);
+                try {
+                    callback.onOperationComplete(
+                            USB_OPERATION_ERROR_PORT_MISMATCH);
+                } catch (RemoteException e) {
+                    logAndPrintException(pw,
+                            "resetUsbPort: Failed to call OperationComplete. opId:"
+                            + transactionId, e);
+                }
+                return false;
+            }
+
+            try {
+                try {
+                    return mUsbPortHal.resetUsbPort(portId, transactionId, callback);
+                } catch (Exception e) {
+                    logAndPrintException(pw,
+                        "reseetUsbPort: Failed to resetUsbPort. opId:"
+                        + transactionId , e);
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                }
+            } catch (RemoteException e) {
+                logAndPrintException(pw,
+                        "resetUsbPort: Failed to call onOperationComplete. opId:"
+                        + transactionId, e);
+            }
+            return false;
+        }
+    }
+
     public void setPortRoles(String portId, int newPowerRole, int newDataRole,
             IndentingPrintWriter pw) {
         synchronized (mLock) {
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 88ffc7d61..f3308bb 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -680,6 +680,35 @@
     }
 
     @Override
+    public boolean resetUsbPort(String portId, int operationId,
+            IUsbOperationInternal callback) {
+        Objects.requireNonNull(portId, "resetUsbPort: portId must not be null. opId:"
+                + operationId);
+        Objects.requireNonNull(callback, "resetUsbPort: callback must not be null. opId:"
+                + operationId);
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        boolean wait;
+
+        try {
+            if (mPortManager != null) {
+                wait = mPortManager.resetUsbPort(portId, operationId, callback, null);
+            } else {
+                wait = false;
+                try {
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "resetUsbPort: Failed to call onOperationComplete", e);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return wait;
+    }
+
+    @Override
     public List<ParcelableUsbPort> getPorts() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
 
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 6e68a91..3412a6f 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -870,35 +870,4 @@
         return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
     }
 
-    /**
-     * isDock() indicates if the connected USB output peripheral is a docking station with
-     * audio output.
-     * A valid audio dock must declare only one audio output control terminal of type
-     * TERMINAL_EXTERN_DIGITAL.
-     */
-    public boolean isDock() {
-        if (hasMIDIInterface() || hasHIDInterface()) {
-            return false;
-        }
-
-        ArrayList<UsbDescriptor> acDescriptors =
-                getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
-                        UsbACInterface.AUDIO_AUDIOCONTROL);
-
-        if (acDescriptors.size() != 1) {
-            return false;
-        }
-
-        if (acDescriptors.get(0) instanceof UsbACTerminal) {
-            UsbACTerminal outDescr = (UsbACTerminal) acDescriptors.get(0);
-            if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_DIGITAL) {
-                return true;
-            }
-        } else {
-            Log.w(TAG, "Undefined Audio Output terminal l: " + acDescriptors.get(0).getLength()
-                    + " t:0x" + Integer.toHexString(acDescriptors.get(0).getType()));
-        }
-        return false;
-    }
-
 }
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index 5582600..f468db3 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -238,6 +238,50 @@
     }
 
     @Override
+    public boolean resetUsbPort(String portName, long operationID,
+            IUsbOperationInternal callback) {
+        Objects.requireNonNull(portName);
+        Objects.requireNonNull(callback);
+        long key = operationID;
+        synchronized (mLock) {
+            try {
+                if (mProxy == null) {
+                    logAndPrint(Log.ERROR, mPw,
+                            "resetUsbPort: Proxy is null. Retry !opID:"
+                            + operationID);
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                    return false;
+                }
+                while (sCallbacks.get(key) != null) {
+                    key = ThreadLocalRandom.current().nextInt();
+                }
+                if (key != operationID) {
+                    logAndPrint(Log.INFO, mPw, "resetUsbPort: operationID exists ! opID:"
+                            + operationID + " key:" + key);
+                }
+                try {
+                    sCallbacks.put(operationID, callback);
+                    mProxy.resetUsbPort(portName, operationID);
+                } catch (RemoteException e) {
+                    logAndPrintException(mPw,
+                            "resetUsbPort: Failed to resetUsbPort: portID="
+                            + portName + "opId:" + operationID, e);
+                    callback.onOperationComplete(USB_OPERATION_ERROR_INTERNAL);
+                    sCallbacks.remove(key);
+                    return false;
+                }
+            } catch (RemoteException e) {
+                logAndPrintException(mPw,
+                        "resetUsbPort: Failed to call onOperationComplete portID="
+                        + portName + "opID:" + operationID, e);
+                sCallbacks.remove(key);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    @Override
     public boolean enableUsbData(String portName, boolean enable, long operationID,
             IUsbOperationInternal callback) {
         Objects.requireNonNull(portName);
@@ -605,5 +649,27 @@
                         e);
             }
         }
+
+        @Override
+        public void notifyResetUsbPortStatus(String portName, int retval,
+                long operationID) {
+            if (retval == Status.SUCCESS) {
+                UsbPortManager.logAndPrint(Log.INFO, mPw, "notifyResetUsbPortStatus:"
+                        + portName + ": opID:" + operationID);
+            } else {
+                UsbPortManager.logAndPrint(Log.ERROR, mPw, portName
+                        + "notifyEnableUsbDataStatus: opID:"
+                        + operationID + " failed. err:" + retval);
+            }
+            try {
+                sCallbacks.get(operationID).onOperationComplete(retval == Status.SUCCESS
+                        ? USB_OPERATION_SUCCESS
+                        : USB_OPERATION_ERROR_INTERNAL);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw,
+                        "notifyResetUsbPortStatus: Failed to call onOperationComplete",
+                        e);
+            }
+        }
     }
 }
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
index abfdd6f..4fa296d 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHal.java
@@ -193,4 +193,18 @@
      */
     public void enableLimitPowerTransfer(String portName, boolean limit, long transactionId,
             IUsbOperationInternal callback);
+
+    /**
+     * Invoked to reset UsbData on the specified port.
+     *
+     * @param portName Port Identifier.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     * @param callback callback object to be invoked to invoke the status of the operation upon
+     *                 completion.
+     * @param callback callback object to be invoked to invoke the status of the operation upon
+     *                 completion.
+     */
+    public boolean resetUsbPort(String portName, long transactionId,
+            IUsbOperationInternal callback);
 }
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index c1d7635..64e8adc 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -318,6 +318,19 @@
     }
 
     @Override
+    public boolean resetUsbPort(String portName, long transactionId,
+            IUsbOperationInternal callback) {
+        try {
+            callback.onOperationComplete(USB_OPERATION_ERROR_NOT_SUPPORTED);
+        } catch (RemoteException e) {
+            logAndPrintException(mPw, "Failed to call onOperationComplete. opID:"
+                    + transactionId
+                    + " portId:" + portName, e);
+        }
+        return false;
+    }
+
+    @Override
     public boolean enableUsbData(String portName, boolean enable, long transactionId,
             IUsbOperationInternal callback) {
         int halVersion;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index e332d3f..ec18c6a 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -380,7 +380,45 @@
      */
     public static final int CAPABILITY_CALL_COMPOSER = 0x8000;
 
-    /* NEXT CAPABILITY: 0x10000 */
+    /**
+     * Flag indicating that this {@link PhoneAccount} provides SIM-based voice calls, potentially as
+     * an over-the-top solution such as wi-fi calling.
+     *
+     * <p>Similar to {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING}, this capability indicates this
+     * {@link PhoneAccount} has the ability to make voice calls (but not necessarily at this time).
+     * Whether this {@link PhoneAccount} can make a voice call is ultimately controlled by {@link
+     * #CAPABILITY_VOICE_CALLING_AVAILABLE}, which indicates whether this {@link PhoneAccount} is
+     * currently capable of making a voice call. Consider a case where, for example, a {@link
+     * PhoneAccount} supports making voice calls (e.g. {@link
+     * #CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS}), but a current lack of network connectivity
+     * prevents voice calls from being made (e.g. {@link #CAPABILITY_VOICE_CALLING_AVAILABLE}).
+     *
+     * <p>In order to declare this capability, this {@link PhoneAccount} must also declare {@link
+     * #CAPABILITY_SIM_SUBSCRIPTION} or {@link #CAPABILITY_CONNECTION_MANAGER} and satisfy the
+     * associated requirements.
+     *
+     * @see #CAPABILITY_VOICE_CALLING_AVAILABLE
+     * @see #getCapabilities
+     */
+    public static final int CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS = 0x10000;
+
+    /**
+     * Flag indicating that this {@link PhoneAccount} is <em>currently</em> able to place SIM-based
+     * voice calls, similar to {@link #CAPABILITY_VIDEO_CALLING}.
+     *
+     * <p>See also {@link #CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS}, which indicates whether
+     * the {@code PhoneAccount} supports placing SIM-based voice calls or not.
+     *
+     * <p>In order to declare this capability, this {@link PhoneAccount} must also declare {@link
+     * #CAPABILITY_SIM_SUBSCRIPTION} or {@link #CAPABILITY_CONNECTION_MANAGER} and satisfy the
+     * associated requirements.
+     *
+     * @see #CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
+     * @see #getCapabilities
+     */
+    public static final int CAPABILITY_VOICE_CALLING_AVAILABLE = 0x20000;
+
+    /* NEXT CAPABILITY: 0x40000 */
 
     /**
      * URI scheme for telephone number URIs.
@@ -1102,14 +1140,20 @@
             sb.append("SimSub ");
         }
         if (hasCapabilities(CAPABILITY_RTT)) {
-            sb.append("Rtt");
+            sb.append("Rtt ");
         }
         if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) {
-            sb.append("AdhocConf");
+            sb.append("AdhocConf ");
         }
         if (hasCapabilities(CAPABILITY_CALL_COMPOSER)) {
             sb.append("CallComposer ");
         }
+        if (hasCapabilities(CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS)) {
+            sb.append("SuppVoice ");
+        }
+        if (hasCapabilities(CAPABILITY_VOICE_CALLING_AVAILABLE)) {
+            sb.append("Voice ");
+        }
         return sb.toString();
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d5c846d..7ba4b11 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5186,6 +5186,20 @@
         public static final int E911_RTP_INACTIVITY_ON_CONNECTED = 4;
 
         /**
+         * List of different RAT technologies on which IMS
+         * is supported.
+         *
+         * <p>Possible values are,
+         * {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
+         * {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
+         * {@link AccessNetworkConstants.AccessNetworkType#IWLAN}
+         * {@link AccessNetworkConstants.AccessNetworkType#UTRAN}
+         * {@link AccessNetworkConstants.AccessNetworkType#GERAN}
+         */
+        public static final String KEY_SUPPORTED_RATS_INT_ARRAY =
+                KEY_PREFIX + "supported_rats_int_array";
+
+        /**
          * A bundle which specifies the MMTEL capability and registration technology
          * that requires provisioning. If a tuple is not present, the
          * framework will not require that the tuple requires provisioning before
@@ -5375,6 +5389,13 @@
                     new int[] {
                         GEOLOCATION_PIDF_FOR_EMERGENCY_ON_WIFI
                     });
+            defaults.putIntArray(
+                    KEY_SUPPORTED_RATS_INT_ARRAY,
+                    new int[] {
+                        AccessNetworkType.NGRAN,
+                        AccessNetworkType.EUTRAN,
+                        AccessNetworkType.IWLAN
+                    });
 
             defaults.putString(KEY_PHONE_CONTEXT_DOMAIN_NAME_STRING, "");
             defaults.putString(KEY_IMS_USER_AGENT_STRING,
@@ -5499,6 +5520,44 @@
         public static final String KEY_SESSION_REFRESHER_TYPE_INT =
                 KEY_PREFIX + "session_refresher_type_int";
 
+
+        /** @hide */
+        @IntDef({
+            SESSION_PRIVACY_TYPE_HEADER,
+            SESSION_PRIVACY_TYPE_NONE,
+            SESSION_PRIVACY_TYPE_ID
+        })
+
+        public @interface SessionPrivacyType {}
+
+        /**
+         * Session privacy type is HEADER as per RFC 3323 Section 4.2.
+         */
+        public static final int SESSION_PRIVACY_TYPE_HEADER = 0;
+
+        /**
+         * Session privacy type is NONE as per RFC 3323 Section 4.2.
+         */
+        public static final int SESSION_PRIVACY_TYPE_NONE = 1;
+
+        /**
+         * Session privacy type is ID as per RFC 3325 Section 9.3.
+         */
+        public static final int SESSION_PRIVACY_TYPE_ID = 2;
+
+        /**
+         * Specify the session privacy type.
+         *
+         * <p>Reference: RFC 3323 Section 4.2, RFC 3325 Section 9.3.
+         *
+         * <p>Possible values are,
+         * {@link #SESSION_PRIVACY_TYPE_HEADER},
+         * {@link #SESSION_PRIVACY_TYPE_NONE},
+         * {@link #SESSION_PRIVACY_TYPE_ID}
+         */
+        public static final String KEY_SESSION_PRIVACY_TYPE_INT =
+                KEY_PREFIX + "session_privacy_type_int";
+
         /**
          * Flag indicating whether PRACK must be enabled for all 18x messages.
          *
@@ -6320,6 +6379,7 @@
             defaults.putBoolean(KEY_VOICE_ON_DEFAULT_BEARER_SUPPORTED_BOOL, false);
 
             defaults.putInt(KEY_SESSION_REFRESHER_TYPE_INT, SESSION_REFRESHER_TYPE_UNKNOWN);
+            defaults.putInt(KEY_SESSION_PRIVACY_TYPE_INT, SESSION_PRIVACY_TYPE_HEADER);
             defaults.putInt(KEY_SESSION_REFRESH_METHOD_INT,
                             SESSION_REFRESH_METHOD_UPDATE_PREFERRED);
             defaults.putInt(KEY_CONFERENCE_SUBSCRIBE_TYPE_INT,
@@ -6567,22 +6627,6 @@
                 KEY_PREFIX + "text_rr_bandwidth_bps_int";
 
         /**
-         * List of various reasons for RTT call to end due to
-         * media inactivity.
-         *
-         * <p>Possible values are,
-         * <UL>
-         *     <LI>{@link Ims#RTCP_INACTIVITY_ON_HOLD}</LI>
-         *     <LI>{@link Ims#RTCP_INACTIVITY_ON_CONNECTED}</LI>
-         *     <LI>{@link Ims#RTP_INACTIVITY_ON_CONNECTED}</LI>
-         *     <LI>{@link Ims#E911_RTCP_INACTIVITY_ON_CONNECTED}</LI>
-         *     <LI>{@link Ims#E911_RTP_INACTIVITY_ON_CONNECTED}</LI>
-         * </UL>
-         */
-        public static final String KEY_TEXT_INACTIVITY_CALL_END_REASONS_INT_ARRAY =
-                KEY_PREFIX + "text_inactivity_call_end_reasons_int_array";
-
-        /**
          * Specifies the Text Codec capability.
          *
          * <p>Possible keys in this bundle are,
@@ -6617,13 +6661,6 @@
             defaults.putInt(KEY_TEXT_RS_BANDWIDTH_BPS_INT, 100);
             defaults.putInt(KEY_TEXT_RR_BANDWIDTH_BPS_INT, 300);
 
-            defaults.putIntArray(
-                    KEY_TEXT_INACTIVITY_CALL_END_REASONS_INT_ARRAY,
-                    new int[] {
-                        Ims.RTCP_INACTIVITY_ON_CONNECTED,
-                        Ims.RTP_INACTIVITY_ON_CONNECTED
-                    });
-
             PersistableBundle text_codec_capability_payload_types = new PersistableBundle();
 
             text_codec_capability_payload_types.putInt(
@@ -6707,6 +6744,13 @@
         public static final String KEY_EMERGENCY_REGISTRATION_TIMER_MILLIS_INT =
                 KEY_PREFIX + "emergency_registration_timer_millis_int";
 
+        /**
+         * This setting will be specify the wait time for refreshing
+         * geolocation information before dialing emergency call.
+         */
+        public static final String KEY_REFRESH_GEOLOCATION_TIMEOUT_MILLIS_INT =
+                KEY_PREFIX + "refresh_geolocation_timeout_millis_int";
+
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putBoolean(KEY_RETRY_EMERGENCY_ON_IMS_PDN_BOOL, false);
@@ -6721,6 +6765,7 @@
                     });
 
             defaults.putInt(KEY_EMERGENCY_REGISTRATION_TIMER_MILLIS_INT, 20000);
+            defaults.putInt(KEY_REFRESH_GEOLOCATION_TIMEOUT_MILLIS_INT, 5000);
 
             return defaults;
         }
@@ -7035,6 +7080,17 @@
                 KEY_PREFIX + "ut_requires_ims_registration_bool";
 
         /**
+         * Flag that controls whether XCAP over UT is supported
+         * when on roaming network.
+         *
+         * <p>If {@code true}: XCAP over UT is supported when on
+         * roaming network.
+         * {@code false} otherwise.
+         */
+        public static final String KEY_UT_SUPPORTED_WHEN_ROAMING_BOOL =
+                KEY_PREFIX + "ut_supported_when_roaming_bool";
+
+        /**
          * Flag that controls whether Circuit Switched Fallback (CSFB)
          * option is available when XCAP over UT fails.
          *
@@ -7385,6 +7441,7 @@
             defaults.putBoolean(KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL, true);
             defaults.putBoolean(KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL, true);
             defaults.putBoolean(KEY_NETWORK_INITIATED_USSD_OVER_IMS_SUPPORTED_BOOL, true);
+            defaults.putBoolean(KEY_UT_SUPPORTED_WHEN_ROAMING_BOOL, true);
 
             defaults.putInt(KEY_UT_IPTYPE_HOME_INT, ApnSetting.PROTOCOL_IPV4V6);
             defaults.putInt(KEY_UT_IPTYPE_ROAMING_INT, ApnSetting.PROTOCOL_IPV4V6);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 56bf303..3a3b363 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1083,6 +1083,13 @@
      */
     public static final int REQUEST_NOT_SUPPORTED = 0x1000A;
 
+    /**
+     * An internal setup data error initiated by telephony that no retry should be performed.
+     *
+     * @hide
+     */
+    public static final int NO_RETRY_FAILURE = 0x1000B;
+
     private static final Map<Integer, String> sFailCauseMap;
     static {
         sFailCauseMap = new HashMap<>();
@@ -1515,6 +1522,8 @@
         sFailCauseMap.put(DUPLICATE_CID, "DUPLICATE_CID");
         sFailCauseMap.put(NO_DEFAULT_DATA, "NO_DEFAULT_DATA");
         sFailCauseMap.put(SERVICE_TEMPORARILY_UNAVAILABLE, "SERVICE_TEMPORARILY_UNAVAILABLE");
+        sFailCauseMap.put(REQUEST_NOT_SUPPORTED, "REQUEST_NOT_SUPPORTED");
+        sFailCauseMap.put(NO_RETRY_FAILURE, "NO_RETRY_FAILURE");
     }
 
     private DataFailCause() {
@@ -1565,6 +1574,7 @@
     }
 
     /** @hide */
+    // TODO: Migrated to DataConfigManager
     public static boolean isPermanentFailure(@NonNull Context context,
                                              @DataFailureCause int failCause,
                                              int subId) {
@@ -1621,6 +1631,7 @@
                     };
                 }
 
+                permanentFailureSet.add(NO_RETRY_FAILURE);
                 sPermanentFailureCache.put(subId, permanentFailureSet);
             }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 536517c..edb817e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -150,7 +150,6 @@
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
-
 /**
  * Provides access to information about the telephony services on
  * the device. Applications can use the methods in this class to
@@ -16805,4 +16804,37 @@
         }
         mTelephonyRegistryMgr.removeCarrierPrivilegesListener(listener);
     }
+
+    /**
+     * Sets a voice service state override from telecom based on the current {@link PhoneAccount}s
+     * registered. See {@link PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE}.
+     *
+     * <p>Currently, this API is only called to indicate over-the-top voice calling capability of
+     * the SIM call manager, which will get merged into {@link ServiceState#getState} and propagated
+     * to interested callers via {@link #getServiceState} and {@link
+     * TelephonyCallback.ServiceStateListener}.
+     *
+     * <p>If callers are truly interested in the actual device <-> tower connection status and not
+     * an overall "device can make voice calls" boolean, they can use {@link
+     * ServiceState#getNetworkRegistrationInfo} to check CS registration state.
+     *
+     * <p>TODO(b/215240050) In the future, this API will be removed and replaced with a new superset
+     * API to disentangle the "true" {@link ServiceState} meaning of "this is the connection status
+     * to the tower" from IMS registration state and over-the-top voice calling capabilities.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE)
+    public void setVoiceServiceStateOverride(boolean hasService) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) {
+                throw new IllegalStateException("Telephony service is null");
+            }
+            telephony.setVoiceServiceStateOverride(getSubId(), hasService, getOpPackageName());
+        } catch (RemoteException ex) {
+            ex.rethrowAsRuntimeException();
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bce7a24..dc96b35 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2543,4 +2543,10 @@
      * registration technology specified, false if it is not required.
      */
     boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech);
+
+    /**
+     * Sets a voice service state from telecom based on the current PhoneAccounts registered. See
+     * PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE.
+     */
+    void setVoiceServiceStateOverride(int subId, boolean hasService, String callingPackage);
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 8de38f6..294a220 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -27,6 +27,7 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -91,6 +92,13 @@
         super.statusBarLayerRotatesScales()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun statusBarLayerRotatesScales_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.statusBarLayerRotatesScales()
+    }
+
     /** {@inheritDoc} */
     @Presubmit
     @Test
@@ -100,6 +108,13 @@
         super.launcherLayerReplacesApp()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun launcherLayerReplacesApp_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.launcherLayerReplacesApp()
+    }
+
     /** {@inheritDoc} */
     @Presubmit
     @Test
@@ -109,6 +124,13 @@
         super.entireScreenCovered()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun entireScreenCovered_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.entireScreenCovered()
+    }
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index d960e94..519bd56 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -26,6 +26,7 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -90,6 +91,13 @@
         super.statusBarLayerRotatesScales()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun statusBarLayerRotatesScales_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.statusBarLayerRotatesScales()
+    }
+
     /** {@inheritDoc} */
     @Presubmit
     @Test
@@ -99,6 +107,13 @@
         super.launcherLayerReplacesApp()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun launcherLayerReplacesApp_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.launcherLayerReplacesApp()
+    }
+
     /** {@inheritDoc} */
     @Presubmit
     @Test
@@ -108,6 +123,13 @@
         super.entireScreenCovered()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun entireScreenCovered_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.entireScreenCovered()
+    }
+
     /** {@inheritDoc} */
     @Presubmit
     @Test
@@ -117,6 +139,13 @@
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
     }
 
+    @FlakyTest(bugId = 214452854)
+    @Test
+    fun visibleLayersShownMoreThanOneConsecutiveEntry_shellTransit() {
+        assumeTrue(isShellTransitionsEnabled)
+        super.visibleLayersShownMoreThanOneConsecutiveEntry()
+    }
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 01fce05..42941c2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -40,6 +40,7 @@
 import com.android.server.wm.traces.common.FlickerComponentName
 import com.android.server.wm.traces.common.Rect
 import org.junit.Assume
+import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -62,7 +63,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group1
-class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestParameter) {
+open class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestParameter) {
     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
 
     private val testApp1 = SimpleAppHelper(instrumentation)
@@ -85,9 +86,9 @@
                         ?: error("Display not found")
 
                     // Swipe right from bottom to quick switch back
-                    // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
-                    // as to not accidentally trigger a swipe back or forward action which would result
-                    // in the same behavior but not testing quick swap.
+                    // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the
+                    // middle as to not accidentally trigger a swipe back or forward action which
+                    // would result in the same behavior but not testing quick swap.
                     device.swipe(
                             startDisplayBounds.right / 3,
                             startDisplayBounds.bottom,
@@ -126,15 +127,19 @@
         }
     }
 
+    @Before
+    open fun setup() {
+        // This test doesn't work in shell transitions because of b/213867585
+        Assume.assumeFalse(isShellTransitionsEnabled)
+    }
+
     /**
      * Checks that the transition starts with [testApp1]'s windows filling/covering exactly the
      * entirety of the display.
      */
     @Presubmit
     @Test
-    fun startsWithApp1WindowsCoverFullScreen() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun startsWithApp1WindowsCoverFullScreen() {
         testSpec.assertWmStart {
             this.frameRegion(testApp1.component, FlickerComponentName.LETTERBOX)
                 .coversExactly(startDisplayBounds)
@@ -147,9 +152,7 @@
      */
     @Presubmit
     @Test
-    fun startsWithApp1LayersCoverFullScreen() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun startsWithApp1LayersCoverFullScreen() {
         testSpec.assertLayersStart {
             this.visibleRegion(testApp1.component).coversExactly(startDisplayBounds)
         }
@@ -160,23 +163,19 @@
      */
     @Presubmit
     @Test
-    fun startsWithApp1WindowBeingOnTop() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun startsWithApp1WindowBeingOnTop() {
         testSpec.assertWmStart {
             this.isAppWindowOnTop(testApp1.component)
         }
     }
 
     /**
-     * Checks that [testApp2] windows fill the entire screen (i.e. is "fullscreen") at the end of the
-     * transition once we have fully quick switched from [testApp1] back to the [testApp2].
+     * Checks that [testApp2] windows fill the entire screen (i.e. is "fullscreen") at the end of
+     * the transition once we have fully quick switched from [testApp1] back to the [testApp2].
      */
     @Presubmit
     @Test
-    fun endsWithApp2WindowsCoveringFullScreen() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun endsWithApp2WindowsCoveringFullScreen() {
         testSpec.assertWmEnd {
             this.frameRegion(testApp2.component).coversExactly(startDisplayBounds)
         }
@@ -188,9 +187,7 @@
      */
     @Presubmit
     @Test
-    fun endsWithApp2LayersCoveringFullScreen() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun endsWithApp2LayersCoveringFullScreen() {
         testSpec.assertLayersEnd {
             this.visibleRegion(testApp2.component, FlickerComponentName.LETTERBOX)
                 .coversExactly(startDisplayBounds)
@@ -198,14 +195,12 @@
     }
 
     /**
-     * Checks that [testApp2] is the top window at the end of the transition once we have fully quick
-     * switched from [testApp1] back to the [testApp2].
+     * Checks that [testApp2] is the top window at the end of the transition once we have fully
+     * quick switched from [testApp1] back to the [testApp2].
      */
     @Presubmit
     @Test
-    fun endsWithApp2BeingOnTop() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun endsWithApp2BeingOnTop() {
         testSpec.assertWmEnd {
             this.isAppWindowOnTop(testApp2.component)
         }
@@ -217,9 +212,7 @@
      */
     @Presubmit
     @Test
-    fun app2WindowBecomesAndStaysVisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun app2WindowBecomesAndStaysVisible() {
         testSpec.assertWm {
             this.isAppWindowInvisible(testApp2.component)
                     .then()
@@ -235,9 +228,7 @@
      */
     @Presubmit
     @Test
-    fun app2LayerBecomesAndStaysVisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun app2LayerBecomesAndStaysVisible() {
         testSpec.assertLayers {
             this.isInvisible(testApp2.component)
                     .then()
@@ -251,9 +242,7 @@
      */
     @Presubmit
     @Test
-    fun app1WindowBecomesAndStaysInvisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun app1WindowBecomesAndStaysInvisible() {
         testSpec.assertWm {
             this.isAppWindowVisible(testApp1.component)
                     .then()
@@ -267,9 +256,7 @@
      */
     @Presubmit
     @Test
-    fun app1LayerBecomesAndStaysInvisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun app1LayerBecomesAndStaysInvisible() {
         testSpec.assertLayers {
             this.isVisible(testApp1.component)
                     .then()
@@ -284,9 +271,7 @@
      */
     @Presubmit
     @Test
-    fun app2WindowIsVisibleOnceApp1WindowIsInvisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun app2WindowIsVisibleOnceApp1WindowIsInvisible() {
         testSpec.assertWm {
             this.isAppWindowVisible(testApp1.component)
                     .then()
@@ -305,9 +290,7 @@
      */
     @Presubmit
     @Test
-    fun app2LayerIsVisibleOnceApp1LayerIsInvisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun app2LayerIsVisibleOnceApp1LayerIsInvisible() {
         testSpec.assertLayers {
             this.isVisible(testApp1.component)
                     .then()
@@ -324,9 +307,7 @@
      */
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun navBarWindowIsAlwaysVisible() {
         testSpec.navBarWindowIsVisible()
     }
 
@@ -335,9 +316,7 @@
      */
     @Presubmit
     @Test
-    fun navBarLayerAlwaysIsVisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun navBarLayerAlwaysIsVisible() {
         testSpec.navBarLayerIsVisible()
     }
 
@@ -348,9 +327,7 @@
      */
     @Presubmit
     @Test
-    fun navbarIsAlwaysInRightPosition() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun navbarIsAlwaysInRightPosition() {
         testSpec.navBarLayerRotatesAndScales()
     }
 
@@ -359,9 +336,7 @@
      */
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun statusBarWindowIsAlwaysVisible() {
         testSpec.statusBarWindowIsVisible()
     }
 
@@ -370,9 +345,7 @@
      */
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() {
-        // This test doesn't work in shell transitions because of b/209936664
-        Assume.assumeFalse(isShellTransitionsEnabled)
+    open fun statusBarLayerIsAlwaysVisible() {
         testSpec.statusBarLayerIsVisible()
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt
new file mode 100644
index 0000000..49b9733
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestShellTransit.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.flicker.quickswitch
+
+import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching back to previous app from last opened app
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsForwardTestShellTransit`
+ *
+ * Actions:
+ *     Launch an app [testApp1]
+ *     Launch another app [testApp2]
+ *     Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
+ *     Swipe left from the bottom of the screen to quick switch forward to the second app [testApp2]
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class QuickSwitchBetweenTwoAppsForwardTestShellTransit(private val testSpec: FlickerTestParameter)
+    : QuickSwitchBetweenTwoAppsForwardTest(testSpec) {
+
+    @Before
+    override fun setup() {
+        // This test class should be removed after b/213867585 is fixed.
+        Assume.assumeTrue(isShellTransitionsEnabled)
+    }
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun startsWithApp1WindowsCoverFullScreen() =
+            super.startsWithApp1WindowsCoverFullScreen()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun startsWithApp1LayersCoverFullScreen() = super.startsWithApp1LayersCoverFullScreen()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun startsWithApp1WindowBeingOnTop() = super.startsWithApp1WindowBeingOnTop()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun endsWithApp2WindowsCoveringFullScreen() =
+            super.endsWithApp2WindowsCoveringFullScreen()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun endsWithApp2LayersCoveringFullScreen() =
+            super.endsWithApp2LayersCoveringFullScreen()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun endsWithApp2BeingOnTop() = super.endsWithApp2BeingOnTop()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun app2WindowBecomesAndStaysVisible() = super.app2WindowBecomesAndStaysVisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun app2LayerBecomesAndStaysVisible() = super.app2LayerBecomesAndStaysVisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun app1WindowBecomesAndStaysInvisible() = super.app1WindowBecomesAndStaysInvisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun app1LayerBecomesAndStaysInvisible() = super.app1LayerBecomesAndStaysInvisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun app2WindowIsVisibleOnceApp1WindowIsInvisible() =
+            super.app2WindowIsVisibleOnceApp1WindowIsInvisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun app2LayerIsVisibleOnceApp1LayerIsInvisible() =
+            super.app2LayerIsVisibleOnceApp1LayerIsInvisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun navBarLayerAlwaysIsVisible() = super.navBarLayerAlwaysIsVisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun navbarIsAlwaysInRightPosition() = super.navbarIsAlwaysInRightPosition()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+
+    /** {@inheritDoc}  */
+    @FlakyTest(bugId = 214452854)
+    @Test
+    override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+}
\ No newline at end of file
diff --git a/wifi/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java b/wifi/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
index bb0cc97..21700d5 100644
--- a/wifi/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
+++ b/wifi/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
@@ -42,8 +42,10 @@
     private boolean m80211nSupported;
     private boolean m80211acSupported;
     private boolean m80211axSupported;
+    private boolean m80211beSupported;
     private boolean mChannelWidth160MhzSupported;
     private boolean mChannelWidth80p80MhzSupported;
+    private boolean mChannelWidth320MhzSupported;
     private int mMaxNumberTxSpatialStreams;
     private int mMaxNumberRxSpatialStreams;
 
@@ -53,8 +55,10 @@
         m80211nSupported = false;
         m80211acSupported = false;
         m80211axSupported = false;
+        m80211beSupported = false;
         mChannelWidth160MhzSupported = false;
         mChannelWidth80p80MhzSupported = false;
+        mChannelWidth320MhzSupported = false;
         mMaxNumberTxSpatialStreams = 1;
         mMaxNumberRxSpatialStreams = 1;
     }
@@ -76,6 +80,8 @@
                 return m80211acSupported;
             case ScanResult.WIFI_STANDARD_11AX:
                 return m80211axSupported;
+            case ScanResult.WIFI_STANDARD_11BE:
+                return m80211beSupported;
             default:
                 Log.e(TAG, "isWifiStandardSupported called with invalid standard: " + standard);
                 return false;
@@ -100,6 +106,9 @@
             case ScanResult.WIFI_STANDARD_11AX:
                 m80211axSupported = support;
                 break;
+            case ScanResult.WIFI_STANDARD_11BE:
+                m80211beSupported = support;
+                break;
             default:
                 Log.e(TAG, "setWifiStandardSupport called with invalid standard: " + standard);
         }
@@ -117,13 +126,16 @@
             case ScanResult.CHANNEL_WIDTH_20MHZ:
                 return true;
             case ScanResult.CHANNEL_WIDTH_40MHZ:
-                return (m80211nSupported || m80211acSupported || m80211axSupported);
+                return (m80211nSupported || m80211acSupported || m80211axSupported
+                    || m80211beSupported);
             case ScanResult.CHANNEL_WIDTH_80MHZ:
-                return (m80211acSupported || m80211axSupported);
+                return (m80211acSupported || m80211axSupported || m80211beSupported);
             case ScanResult.CHANNEL_WIDTH_160MHZ:
                 return mChannelWidth160MhzSupported;
             case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
                 return mChannelWidth80p80MhzSupported;
+            case ScanResult.CHANNEL_WIDTH_320MHZ:
+                return mChannelWidth320MhzSupported;
             default:
                 Log.e(TAG, "isChannelWidthSupported called with invalid channel width: " + chWidth);
         }
@@ -133,8 +145,9 @@
     /**
      * Set support for channel bandwidth
      *
-     * @param chWidth valid values are {@link ScanResult#CHANNEL_WIDTH_160MHZ} and
-     *        {@link ScanResult#CHANNEL_WIDTH_80MHZ_PLUS_MHZ}
+     * @param chWidth valid values are {@link ScanResult#CHANNEL_WIDTH_160MHZ},
+     *        {@link ScanResult#CHANNEL_WIDTH_80MHZ_PLUS_MHZ} and
+     *        {@link ScanResult#CHANNEL_WIDTH_320MHZ}
      * @param support {@code true} if supported, {@code false} otherwise.
      *
      * @hide
@@ -147,6 +160,9 @@
             case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
                 mChannelWidth80p80MhzSupported = support;
                 break;
+            case ScanResult.CHANNEL_WIDTH_320MHZ:
+                mChannelWidth320MhzSupported = support;
+                break;
             default:
                 Log.e(TAG, "setChannelWidthSupported called with Invalid channel width: "
                         + chWidth);
@@ -205,8 +221,10 @@
         return m80211nSupported == capa.m80211nSupported
                 && m80211acSupported == capa.m80211acSupported
                 && m80211axSupported == capa.m80211axSupported
+                && m80211beSupported == capa.m80211beSupported
                 && mChannelWidth160MhzSupported == capa.mChannelWidth160MhzSupported
                 && mChannelWidth80p80MhzSupported == capa.mChannelWidth80p80MhzSupported
+                && mChannelWidth320MhzSupported == capa.mChannelWidth320MhzSupported
                 && mMaxNumberTxSpatialStreams == capa.mMaxNumberTxSpatialStreams
                 && mMaxNumberRxSpatialStreams == capa.mMaxNumberRxSpatialStreams;
     }
@@ -215,8 +233,9 @@
     @Override
     public int hashCode() {
         return Objects.hash(m80211nSupported, m80211acSupported, m80211axSupported,
-                mChannelWidth160MhzSupported, mChannelWidth80p80MhzSupported,
-                mMaxNumberTxSpatialStreams, mMaxNumberRxSpatialStreams);
+                m80211beSupported, mChannelWidth160MhzSupported, mChannelWidth80p80MhzSupported,
+                mChannelWidth320MhzSupported, mMaxNumberTxSpatialStreams,
+                mMaxNumberRxSpatialStreams);
     }
 
     /** implement Parcelable interface */
@@ -234,8 +253,10 @@
         out.writeBoolean(m80211nSupported);
         out.writeBoolean(m80211acSupported);
         out.writeBoolean(m80211axSupported);
+        out.writeBoolean(m80211beSupported);
         out.writeBoolean(mChannelWidth160MhzSupported);
         out.writeBoolean(mChannelWidth80p80MhzSupported);
+        out.writeBoolean(mChannelWidth320MhzSupported);
         out.writeInt(mMaxNumberTxSpatialStreams);
         out.writeInt(mMaxNumberRxSpatialStreams);
     }
@@ -246,10 +267,13 @@
         sb.append("m80211nSupported:").append(m80211nSupported ? "Yes" : "No");
         sb.append("m80211acSupported:").append(m80211acSupported ? "Yes" : "No");
         sb.append("m80211axSupported:").append(m80211axSupported ? "Yes" : "No");
+        sb.append("m80211beSupported:").append(m80211beSupported ? "Yes" : "No");
         sb.append("mChannelWidth160MhzSupported: ")
                 .append(mChannelWidth160MhzSupported ? "Yes" : "No");
         sb.append("mChannelWidth80p80MhzSupported: ")
                 .append(mChannelWidth80p80MhzSupported ? "Yes" : "No");
+        sb.append("mChannelWidth320MhzSupported: ")
+                .append(mChannelWidth320MhzSupported ? "Yes" : "No");
         sb.append("mMaxNumberTxSpatialStreams: ").append(mMaxNumberTxSpatialStreams);
         sb.append("mMaxNumberRxSpatialStreams: ").append(mMaxNumberRxSpatialStreams);
 
@@ -268,8 +292,10 @@
             capabilities.m80211nSupported = in.readBoolean();
             capabilities.m80211acSupported = in.readBoolean();
             capabilities.m80211axSupported = in.readBoolean();
+            capabilities.m80211beSupported = in.readBoolean();
             capabilities.mChannelWidth160MhzSupported = in.readBoolean();
             capabilities.mChannelWidth80p80MhzSupported = in.readBoolean();
+            capabilities.mChannelWidth320MhzSupported = in.readBoolean();
             capabilities.mMaxNumberTxSpatialStreams = in.readInt();
             capabilities.mMaxNumberRxSpatialStreams = in.readInt();
             return capabilities;
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index 459696e..d3eb8e0 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -493,6 +493,8 @@
                     return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
                 case IApInterfaceEventCallback.BANDWIDTH_160:
                     return SoftApInfo.CHANNEL_WIDTH_160MHZ;
+                case IApInterfaceEventCallback.BANDWIDTH_320:
+                    return SoftApInfo.CHANNEL_WIDTH_320MHZ;
                 default:
                     return SoftApInfo.CHANNEL_WIDTH_INVALID;
             }