Merge "[lint] exempt Bluetooth from using non-*forUser Settings methods"
diff --git a/Android.bp b/Android.bp
index 25238e8..d5d5150 100644
--- a/Android.bp
+++ b/Android.bp
@@ -155,32 +155,9 @@
     name: "framework-all",
     installable: false,
     static_libs: [
-        "android.net.ipsec.ike.impl",
+        "all-framework-module-impl",
         "framework-minus-apex",
-        "framework-appsearch.impl",
-        "framework-connectivity.impl",
-        "framework-connectivity-tiramisu.impl",
-        "framework-graphics.impl",
-        "framework-mediaprovider.impl",
-        "framework-permission.impl",
-        "framework-permission-s.impl",
-        "framework-scheduling.impl",
-        "framework-sdkextensions.impl",
-        "framework-statsd.impl",
-        "framework-supplementalprocess.impl",
-        "framework-tethering.impl",
-        "framework-uwb.impl",
-        "framework-wifi.impl",
-        "updatable-media",
     ],
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            static_libs: [
-                "framework-auxiliary.impl",
-                "framework-supplementalapi.impl",
-            ],
-        },
-    },
     apex_available: ["//apex_available:platform"],
     sdk_version: "core_platform",
     visibility: [
@@ -418,7 +395,6 @@
     static_libs: [
         "app-compat-annotations",
         "framework-minus-apex",
-        "framework-appsearch.impl", // TODO(b/146218515): should be removed
         "framework-updatable-stubs-module_libs_api",
     ],
     sdk_version: "core_platform",
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index b4edd39..2c2af28 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -66,8 +66,8 @@
     },
     visibility: [
         "//frameworks/av/apex:__subpackages__",
-        "//frameworks/base", // For framework-all
         "//frameworks/base/apex/media/service",
+        "//frameworks/base/api", // For framework-all
     ],
 }
 
diff --git a/api/api.go b/api/api.go
index 17649e8..5e5f60e 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 core_libraries_modules = []string{art, conscrypt, i18n}
 
 // 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
@@ -199,9 +200,28 @@
 	ctx.CreateModule(java.LibraryFactory, &props)
 }
 
-func createMergedModuleLibStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
+	// This module is for the "framework-all" module, which should not include the core libraries.
+	modules = removeAll(modules, core_libraries_modules)
+	// TODO(b/214988855): remove the line below when framework-bluetooth has an impl jar.
+	modules = remove(modules, "framework-bluetooth")
+	props := libraryProps{}
+	props.Name = proptools.StringPtr("all-framework-module-impl")
+	props.Static_libs = transformArray(modules, "", ".impl")
+	// Media module's impl jar is called "updatable-media"
+	for i, v := range props.Static_libs {
+		if v == "framework-media.impl" {
+			props.Static_libs[i] = "updatable-media"
+		}
+	}
+	props.Sdk_version = proptools.StringPtr("module_current")
+	props.Visibility = []string{"//frameworks/base"}
+	ctx.CreateModule(java.LibraryFactory, &props)
+}
+
+func createMergedFrameworkModuleLibStubs(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})
+	modules = removeAll(modules, core_libraries_modules)
 	props := libraryProps{}
 	props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api")
 	props.Static_libs = transformArray(modules, "", ".stubs.module_lib")
@@ -269,7 +289,8 @@
 
 	createMergedPublicStubs(ctx, bootclasspath)
 	createMergedSystemStubs(ctx, bootclasspath)
-	createMergedModuleLibStubs(ctx, bootclasspath)
+	createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
+	createMergedFrameworkImpl(ctx, bootclasspath)
 
 	createMergedAnnotations(ctx, bootclasspath)
 
diff --git a/core/api/current.txt b/core/api/current.txt
index dddf069..a9f1d45 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -135,6 +135,9 @@
     field public static final String READ_HOME_APP_SEARCH_DATA = "android.permission.READ_HOME_APP_SEARCH_DATA";
     field @Deprecated public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
     field public static final String READ_LOGS = "android.permission.READ_LOGS";
+    field public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
+    field public static final String READ_MEDIA_IMAGE = "android.permission.READ_MEDIA_IMAGE";
+    field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
     field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY";
     field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
     field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
@@ -220,6 +223,8 @@
     field public static final String NEARBY_DEVICES = "android.permission-group.NEARBY_DEVICES";
     field public static final String NOTIFICATIONS = "android.permission-group.NOTIFICATIONS";
     field public static final String PHONE = "android.permission-group.PHONE";
+    field public static final String READ_MEDIA_AURAL = "android.permission-group.READ_MEDIA_AURAL";
+    field public static final String READ_MEDIA_VISUAL = "android.permission-group.READ_MEDIA_VISUAL";
     field public static final String SENSORS = "android.permission-group.SENSORS";
     field public static final String SMS = "android.permission-group.SMS";
     field public static final String STORAGE = "android.permission-group.STORAGE";
@@ -3592,17 +3597,17 @@
   }
 
   public static interface Animator.AnimatorListener {
-    method public void onAnimationCancel(android.animation.Animator);
-    method public default void onAnimationEnd(android.animation.Animator, boolean);
-    method public void onAnimationEnd(android.animation.Animator);
-    method public void onAnimationRepeat(android.animation.Animator);
-    method public default void onAnimationStart(android.animation.Animator, boolean);
-    method public void onAnimationStart(android.animation.Animator);
+    method public void onAnimationCancel(@NonNull android.animation.Animator);
+    method public default void onAnimationEnd(@NonNull android.animation.Animator, boolean);
+    method public void onAnimationEnd(@NonNull android.animation.Animator);
+    method public void onAnimationRepeat(@NonNull android.animation.Animator);
+    method public default void onAnimationStart(@NonNull android.animation.Animator, boolean);
+    method public void onAnimationStart(@NonNull android.animation.Animator);
   }
 
   public static interface Animator.AnimatorPauseListener {
-    method public void onAnimationPause(android.animation.Animator);
-    method public void onAnimationResume(android.animation.Animator);
+    method public void onAnimationPause(@NonNull android.animation.Animator);
+    method public void onAnimationResume(@NonNull android.animation.Animator);
   }
 
   public class AnimatorInflater {
@@ -3889,7 +3894,7 @@
   }
 
   public static interface ValueAnimator.AnimatorUpdateListener {
-    method public void onAnimationUpdate(android.animation.ValueAnimator);
+    method public void onAnimationUpdate(@NonNull android.animation.ValueAnimator);
   }
 
 }
@@ -7933,11 +7938,11 @@
   }
 
   public final class WifiSsidPolicy implements android.os.Parcelable {
-    method @NonNull public static android.app.admin.WifiSsidPolicy createAllowlistPolicy(@NonNull java.util.Set<java.lang.String>);
-    method @NonNull public static android.app.admin.WifiSsidPolicy createDenylistPolicy(@NonNull java.util.Set<java.lang.String>);
+    method @NonNull public static android.app.admin.WifiSsidPolicy createAllowlistPolicy(@NonNull java.util.Set<android.net.wifi.WifiSsid>);
+    method @NonNull public static android.app.admin.WifiSsidPolicy createDenylistPolicy(@NonNull java.util.Set<android.net.wifi.WifiSsid>);
     method public int describeContents();
     method public int getPolicyType();
-    method @NonNull public java.util.Set<java.lang.String> getSsids();
+    method @NonNull public java.util.Set<android.net.wifi.WifiSsid> getSsids();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.WifiSsidPolicy> CREATOR;
     field public static final int WIFI_SSID_POLICY_TYPE_ALLOWLIST = 0; // 0x0
@@ -11931,7 +11936,7 @@
     field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
     field public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
     field public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging";
-    field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio";
+    field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
     field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
@@ -15768,9 +15773,9 @@
     method public final void copyBounds(@NonNull android.graphics.Rect);
     method @NonNull public final android.graphics.Rect copyBounds();
     method @Nullable public static android.graphics.drawable.Drawable createFromPath(String);
-    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, String);
+    method @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String);
     method @Deprecated @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String, @Nullable android.graphics.BitmapFactory.Options);
-    method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, String);
+    method @Nullable public static android.graphics.drawable.Drawable createFromStream(@Nullable java.io.InputStream, @Nullable String);
     method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method @NonNull public static android.graphics.drawable.Drawable createFromXmlInner(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -15808,10 +15813,10 @@
     method public final boolean isVisible();
     method public void jumpToCurrentState();
     method @NonNull public android.graphics.drawable.Drawable mutate();
-    method protected void onBoundsChange(android.graphics.Rect);
+    method protected void onBoundsChange(@NonNull android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
-    method protected boolean onStateChange(int[]);
+    method protected boolean onStateChange(@NonNull int[]);
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(@NonNull Runnable, long);
     method public abstract void setAlpha(@IntRange(from=0, to=255) int);
@@ -15972,27 +15977,27 @@
   }
 
   public final class Icon implements android.os.Parcelable {
-    method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
+    method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
     method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull String);
     method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull android.net.Uri);
-    method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
-    method public static android.graphics.drawable.Icon createWithContentUri(String);
-    method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
-    method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
-    method public static android.graphics.drawable.Icon createWithFilePath(String);
-    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int);
-    method public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int);
+    method @NonNull public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
+    method @NonNull public static android.graphics.drawable.Icon createWithContentUri(String);
+    method @NonNull public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
+    method @NonNull public static android.graphics.drawable.Icon createWithData(byte[], int, int);
+    method @NonNull public static android.graphics.drawable.Icon createWithFilePath(String);
+    method @NonNull public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int);
+    method @NonNull public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int);
     method public int describeContents();
     method @DrawableRes public int getResId();
     method @NonNull public String getResPackage();
     method public int getType();
     method @NonNull public android.net.Uri getUri();
-    method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
-    method public void loadDrawableAsync(android.content.Context, android.os.Message);
-    method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
-    method public android.graphics.drawable.Icon setTint(@ColorInt int);
+    method @Nullable public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
+    method public void loadDrawableAsync(@NonNull android.content.Context, @NonNull android.os.Message);
+    method public void loadDrawableAsync(@NonNull android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
+    method @NonNull public android.graphics.drawable.Icon setTint(@ColorInt int);
     method @NonNull public android.graphics.drawable.Icon setTintBlendMode(@NonNull android.graphics.BlendMode);
-    method public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList);
+    method @NonNull public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList);
     method @NonNull public android.graphics.drawable.Icon setTintMode(@NonNull android.graphics.PorterDuff.Mode);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR;
@@ -19679,10 +19684,13 @@
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
 
-  public class AudioDescriptor {
+  public class AudioDescriptor implements android.os.Parcelable {
+    method public int describeContents();
     method @NonNull public byte[] getDescriptor();
     method public int getEncapsulationType();
     method public int getStandard();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDescriptor> CREATOR;
     field public static final int STANDARD_EDID = 1; // 0x1
     field public static final int STANDARD_NONE = 0; // 0x0
   }
@@ -20198,14 +20206,17 @@
     method @NonNull public android.media.AudioPresentation.Builder setProgramId(int);
   }
 
-  public class AudioProfile {
+  public class AudioProfile implements android.os.Parcelable {
+    method public int describeContents();
     method @NonNull public int[] getChannelIndexMasks();
     method @NonNull public int[] getChannelMasks();
     method public int getEncapsulationType();
     method public int getFormat();
     method @NonNull public int[] getSampleRates();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int AUDIO_ENCAPSULATION_TYPE_IEC61937 = 1; // 0x1
     field public static final int AUDIO_ENCAPSULATION_TYPE_NONE = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioProfile> CREATOR;
   }
 
   public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
@@ -42943,6 +42954,7 @@
     field public static final int ENCODING_16BIT = 3; // 0x3
     field public static final int ENCODING_7BIT = 1; // 0x1
     field public static final int ENCODING_8BIT = 2; // 0x2
+    field public static final int ENCODING_KSC5601 = 4; // 0x4
     field public static final int ENCODING_UNKNOWN = 0; // 0x0
     field public static final String FORMAT_3GPP = "3gpp";
     field public static final String FORMAT_3GPP2 = "3gpp2";
@@ -43220,6 +43232,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
     method public int getActiveModemCount();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getAllowedNetworkTypesForReason(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus();
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public int getCallState();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCallStateForSubscription();
@@ -43280,6 +43293,7 @@
     method public int getSubscriptionId();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubscriptionId(@NonNull android.telecom.PhoneAccountHandle);
     method public int getSupportedModemCount();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getSupportedRadioAccessFamily();
     method @Nullable public String getTypeAllocationCode();
     method @Nullable public String getTypeAllocationCode(int);
     method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo();
@@ -43325,6 +43339,7 @@
     method public String sendEnvelopeWithStatus(String);
     method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
     method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
@@ -43361,6 +43376,8 @@
     field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
     field public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
     field public static final String ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED";
+    field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2
+    field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -43435,6 +43452,26 @@
     field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2
     field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
+    field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
+    field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
+    field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
+    field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L
+    field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L
+    field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L
+    field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L
+    field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L
+    field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L
+    field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L
+    field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L
+    field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L
+    field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L
+    field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L
+    field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L
+    field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L
+    field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L
+    field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
+    field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
+    field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
     field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
     field public static final int NETWORK_TYPE_EHRPD = 14; // 0xe
@@ -51430,6 +51467,7 @@
     method public CharSequence getPackageName();
     method public android.view.accessibility.AccessibilityRecord getRecord(int);
     method public int getRecordCount();
+    method public int getSpeechStateChangeTypes();
     method public int getWindowChanges();
     method public void initFromParcel(android.os.Parcel);
     method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int);
@@ -51441,6 +51479,7 @@
     method public void setEventType(int);
     method public void setMovementGranularity(int);
     method public void setPackageName(CharSequence);
+    method public void setSpeechStateChangeTypes(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
     field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
@@ -51456,12 +51495,17 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityEvent> CREATOR;
     field public static final int INVALID_POSITION = -1; // 0xffffffff
     field @Deprecated public static final int MAX_TEXT_LENGTH = 500; // 0x1f4
+    field public static final int SPEECH_STATE_LISTENING_END = 8; // 0x8
+    field public static final int SPEECH_STATE_LISTENING_START = 4; // 0x4
+    field public static final int SPEECH_STATE_SPEAKING_END = 2; // 0x2
+    field public static final int SPEECH_STATE_SPEAKING_START = 1; // 0x1
     field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
     field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
     field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
     field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
     field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
     field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40
+    field public static final int TYPE_SPEECH_STATE_CHANGE = 33554432; // 0x2000000
     field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
     field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
     field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4b9e1c0..71c9452 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1085,6 +1085,7 @@
     method public boolean isDeviceManaged();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean isDpcDownloaded();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isManagedKiosk();
     method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isUnattendedManagedKiosk();
@@ -1097,6 +1098,7 @@
     method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
     method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
@@ -1175,6 +1177,13 @@
     field public static final String UNDEFINED = "UNDEFINED";
   }
 
+  public static final class DevicePolicyResources.Strings.Dialer {
+    field public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+    field public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE = "Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE";
+    field public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE";
+    field public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL = "Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL";
+  }
+
   public static final class DevicePolicyResources.Strings.DocumentsUi {
     field public static final String CANT_SAVE_TO_PERSONAL_MESSAGE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE";
     field public static final String CANT_SAVE_TO_PERSONAL_TITLE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE";
@@ -5926,11 +5935,20 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioAttributes.Builder setSystemUsage(int);
   }
 
+  public class AudioDescriptor implements android.os.Parcelable {
+    ctor public AudioDescriptor(int, int, @NonNull byte[]);
+  }
+
   public final class AudioDeviceAttributes implements android.os.Parcelable {
     ctor public AudioDeviceAttributes(@NonNull android.media.AudioDeviceInfo);
     ctor public AudioDeviceAttributes(int, int, @NonNull String);
+    ctor public AudioDeviceAttributes(int, int, @NonNull String, @NonNull String, @NonNull java.util.List<android.media.AudioProfile>, @NonNull java.util.List<android.media.AudioDescriptor>);
     method public int describeContents();
+    method public boolean equalTypeAddress(@Nullable Object);
     method @NonNull public String getAddress();
+    method @NonNull public java.util.List<android.media.AudioDescriptor> getAudioDescriptors();
+    method @NonNull public java.util.List<android.media.AudioProfile> getAudioProfiles();
+    method @NonNull public String getName();
     method public int getRole();
     method public int getType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -6087,6 +6105,10 @@
     field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff
   }
 
+  public class AudioProfile implements android.os.Parcelable {
+    ctor public AudioProfile(int, @NonNull int[], @NonNull int[], @NonNull int[], int);
+  }
+
   public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
     ctor @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
     method public static long getMaxSharedAudioHistoryMillis();
@@ -9652,7 +9674,7 @@
     method @NonNull public java.util.List<android.os.UserHandle> getAllProfiles();
     method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String, boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getRestrictedProfileParent();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
@@ -9948,7 +9970,8 @@
     method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
     method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, long, int, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
     field @RequiresPermission(android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS) public static final String ACTION_REVIEW_PERMISSION_DECISIONS = "android.permission.action.REVIEW_PERMISSION_DECISIONS";
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -11198,6 +11221,7 @@
     method public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
     method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final void startActivityFromGameSessionForResult(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSessionActivityCallback);
     method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
   }
 
@@ -11207,6 +11231,11 @@
     field public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 0; // 0x0
   }
 
+  public interface GameSessionActivityCallback {
+    method public void onActivityResult(int, @Nullable android.content.Intent);
+    method public default void onActivityStartFailed(@NonNull Throwable);
+  }
+
   public abstract class GameSessionService extends android.app.Service {
     ctor public GameSessionService();
     method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
@@ -12235,6 +12264,7 @@
     field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
     field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
     field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
+    field public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE = "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
     field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
     field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
     field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
@@ -13178,7 +13208,6 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesBitmask();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesForReason(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -13224,7 +13253,6 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimCardState(int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Collection<android.telephony.UiccSlotMapping> getSimSlotMapping();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telephony.RadioAccessSpecifier> getSystemSelectionChannels();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
@@ -13279,7 +13307,6 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
@@ -13329,10 +13356,8 @@
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
-    field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2
     field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3
     field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1
-    field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0
     field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2
     field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
     field public static final int CALL_WAITING_STATUS_FDN_CHECK_FAILURE = 5; // 0x5
@@ -13372,26 +13397,6 @@
     field public static final int KEY_TYPE_WLAN = 2; // 0x2
     field public static final int MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL = 1; // 0x1
     field public static final int MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED = 2; // 0x2
-    field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
-    field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
-    field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
-    field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L
-    field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L
-    field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L
-    field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L
-    field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L
-    field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L
-    field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L
-    field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L
-    field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L
-    field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L
-    field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L
-    field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L
-    field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L
-    field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L
-    field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
-    field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
-    field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
     field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2
     field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3
     field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9d6fc0e..e27fc34 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -511,6 +511,8 @@
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
     field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
     field @Deprecated public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe
+    field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0
+    field public static final int DEVICE_OWNER_TYPE_FINANCED = 1; // 0x1
     field public static final int OPERATION_CLEAR_APPLICATION_USER_DATA = 23; // 0x17
     field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
     field public static final int OPERATION_INSTALL_CA_CERT = 24; // 0x18
@@ -985,7 +987,7 @@
 package android.graphics {
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
-    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, @NonNull java.io.InputStream, int);
   }
 
   public final class Rect implements android.os.Parcelable {
@@ -2518,7 +2520,6 @@
     method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily();
     method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5649c5f..edf9ece 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -176,6 +176,18 @@
         "com/android/internal/util/IndentingPrintWriter.java",
         "com/android/internal/util/MessageUtils.java",
         "com/android/internal/util/WakeupMessage.java",
+        // TODO: delete as soon as NetworkStatsFactory stops using
+        "com/android/internal/util/ProcFileReader.java",
+    ],
+}
+
+// keep these files in sync with the packages/modules/Connectivity jarjar-rules.txt for
+// the connectivity module.
+filegroup {
+    name: "framework-connectivity-api-shared-srcs",
+    srcs: [
+        "android/util/IndentingPrintWriter.java",
+        "com/android/internal/util/FileRotator.java",
     ],
 }
 
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index eb525d3..a8ff36a 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
@@ -535,7 +536,7 @@
          * @param animation The started animation.
          * @param isReverse Whether the animation is playing in reverse.
          */
-        default void onAnimationStart(Animator animation, boolean isReverse) {
+        default void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
             onAnimationStart(animation);
         }
 
@@ -551,7 +552,7 @@
          * @param animation The animation which reached its end.
          * @param isReverse Whether the animation is playing in reverse.
          */
-        default void onAnimationEnd(Animator animation, boolean isReverse) {
+        default void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
             onAnimationEnd(animation);
         }
 
@@ -560,7 +561,7 @@
          *
          * @param animation The started animation.
          */
-        void onAnimationStart(Animator animation);
+        void onAnimationStart(@NonNull Animator animation);
 
         /**
          * <p>Notifies the end of the animation. This callback is not invoked
@@ -568,7 +569,7 @@
          *
          * @param animation The animation which reached its end.
          */
-        void onAnimationEnd(Animator animation);
+        void onAnimationEnd(@NonNull Animator animation);
 
         /**
          * <p>Notifies the cancellation of the animation. This callback is not invoked
@@ -576,14 +577,14 @@
          *
          * @param animation The animation which was canceled.
          */
-        void onAnimationCancel(Animator animation);
+        void onAnimationCancel(@NonNull Animator animation);
 
         /**
          * <p>Notifies the repetition of the animation.</p>
          *
          * @param animation The animation which was repeated.
          */
-        void onAnimationRepeat(Animator animation);
+        void onAnimationRepeat(@NonNull Animator animation);
     }
 
     /**
@@ -599,7 +600,7 @@
          * @param animation The animaton being paused.
          * @see #pause()
          */
-        void onAnimationPause(Animator animation);
+        void onAnimationPause(@NonNull Animator animation);
 
         /**
          * <p>Notifies that the animation was resumed, after being
@@ -608,7 +609,7 @@
          * @param animation The animation being resumed.
          * @see #resume()
          */
-        void onAnimationResume(Animator animation);
+        void onAnimationResume(@NonNull Animator animation);
     }
 
     /**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 3cbae99..06b424b 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -1626,7 +1627,7 @@
          *
          * @param animation The animation which was repeated.
          */
-        void onAnimationUpdate(ValueAnimator animation);
+        void onAnimationUpdate(@NonNull ValueAnimator animation);
 
     }
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 90c56ae..8935022 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5503,6 +5503,17 @@
      */
     public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
             IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
+        startActivityAsCaller(intent, options, permissionToken, ignoreTargetSecurity, userId, -1);
+    }
+
+    /**
+     * @see #startActivityAsCaller(Intent, Bundle, IBinder, boolean, int)
+     * @param requestCode The request code used for returning a result or -1 if no result should be
+     *                    returned.
+     * @hide
+     */
+    public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
+            IBinder permissionToken, boolean ignoreTargetSecurity, int userId, int requestCode) {
         if (mParent != null) {
             throw new RuntimeException("Can't be called from a child");
         }
@@ -5510,11 +5521,11 @@
         Instrumentation.ActivityResult ar =
                 mInstrumentation.execStartActivityAsCaller(
                         this, mMainThread.getApplicationThread(), mToken, this,
-                        intent, -1, options, permissionToken, ignoreTargetSecurity, userId);
+                        intent, requestCode, options, permissionToken, ignoreTargetSecurity,
+                        userId);
         if (ar != null) {
             mMainThread.sendActivityResult(
-                mToken, mEmbeddedID, -1, ar.getResultCode(),
-                ar.getResultData());
+                    mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
         }
         cancelInputsAndStartExitTransition(options);
     }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fdf37f6..0d1bc05 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2363,11 +2363,11 @@
             Manifest.permission.USE_BIOMETRIC,
             Manifest.permission.ACTIVITY_RECOGNITION,
             Manifest.permission.SMS_FINANCIAL_TRANSACTIONS,
-            null,
+            Manifest.permission.READ_MEDIA_AUDIO,
             null, // no permission for OP_WRITE_MEDIA_AUDIO
-            null,
+            Manifest.permission.READ_MEDIA_VIDEO,
             null, // no permission for OP_WRITE_MEDIA_VIDEO
-            null,
+            Manifest.permission.READ_MEDIA_IMAGE,
             null, // no permission for OP_WRITE_MEDIA_IMAGES
             null, // no permission for OP_LEGACY_STORAGE
             null, // no permission for OP_ACCESS_ACCESSIBILITY
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 0801b24..c5add66 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -130,6 +130,9 @@
             in ProfilerInfo profilerInfo, in Bundle options, int userId);
     int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
             int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
+    int startActivityFromGameSession(IApplicationThread caller, in String callingPackage,
+            in String callingFeatureId, int callingPid, int callingUid, in Intent intent,
+            int taskId, int userId);
     void startRecentsActivity(in Intent intent, in long eventTime,
             in IRecentsAnimationRunner recentsAnimationRunner);
     int startActivityFromRecents(int taskId, in Bundle options);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6cd991b..b0883b6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -59,6 +59,7 @@
 import android.net.PrivateDnsConnectivityChecker;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.net.wifi.WifiSsid;
 import android.nfc.NfcAdapter;
 import android.os.Binder;
 import android.os.Build;
@@ -111,6 +112,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
@@ -463,7 +465,9 @@
      * <li>{@link #setUserControlDisabledPackages(ComponentName, List)}</li>
      * <li>{@link #getUserControlDisabledPackages(ComponentName)}</li>
      * <li>{@link #setOrganizationName(ComponentName, CharSequence)}</li>
+     * <li>{@link #getOrganizationName(ComponentName)} </li>
      * <li>{@link #setShortSupportMessage(ComponentName, CharSequence)}</li>
+     * <li>{@link #getShortSupportMessage(ComponentName)}</li>
      * <li>{@link #isBackupServiceEnabled(ComponentName)}</li>
      * <li>{@link #setBackupServiceEnabled(ComponentName, boolean)}</li>
      * <li>{@link #isLockTaskPermitted(String)}</li>
@@ -476,7 +480,9 @@
      *     <li>{@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}</li>
      *     <li>{@link #LOCK_TASK_FEATURE_NOTIFICATIONS}</li>
      * </ul>
+     * <li>{@link #getLockTaskFeatures(ComponentName)}</li>
      * <li>{@link #setLockTaskPackages(ComponentName, String[])}</li>
+     * <li>{@link #getLockTaskPackages(ComponentName)}</li>
      * <li>{@link #addPersistentPreferredActivity(ComponentName, IntentFilter, ComponentName)}</li>
      * <li>{@link #clearPackagePersistentPreferredActivities(ComponentName, String)} </li>
      * <li>{@link #wipeData(int)}</li>
@@ -487,6 +493,10 @@
      * {@link #PERMISSION_GRANT_STATE_GRANTED}, {@link #PERMISSION_GRANT_STATE_DENIED}, or
      * {@link #PERMISSION_GRANT_STATE_DEFAULT} and can <b>only</b> be applied to the device admin
      * app (otherwise a {@link SecurityException} will be thrown)</li>
+     * <li>{@link #getPermissionGrantState(ComponentName, String, String)}, where
+     * {@link permission#READ_PHONE_STATE} is the <b>only</b> permission that can be
+     * used and device admin app is the only package that can be used to retrieve the permission
+     * permission grant state for (otherwise a {@link SecurityException} will be thrown)</li>
      * <li>{@link #addUserRestriction(ComponentName, String)}, where the following user restrictions
      * are permitted (otherwise a {@link SecurityException} will be thrown):</li>
      * <ul>
@@ -497,7 +507,17 @@
      *     <li>{@link UserManager#DISALLOW_CONFIG_DATE_TIME}</li>
      *     <li>{@link UserManager#DISALLOW_OUTGOING_CALLS}</li>
      * </ul>
-     * <li>{@link #clearUserRestriction(ComponentName, String)}</li>
+     * <li>{@link #getUserRestrictions(ComponentName)}</li>
+     * <li>{@link #clearUserRestriction(ComponentName, String)}, where the following user
+     * restrictions are permitted (otherwise a {@link SecurityException} will be thrown):</li>
+     * <ul>
+     *     <li>{@link UserManager#DISALLOW_ADD_USER}</li>
+     *     <li>{@link UserManager#DISALLOW_DEBUGGING_FEATURES}</li>
+     *     <li>{@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES}</li>
+     *     <li>{@link UserManager#DISALLOW_SAFE_BOOT}</li>
+     *     <li>{@link UserManager#DISALLOW_CONFIG_DATE_TIME}</li>
+     *     <li>{@link UserManager#DISALLOW_OUTGOING_CALLS}</li>
+     * </ul>
      * </ul>
      *
      * @hide
@@ -3257,6 +3277,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int DEVICE_OWNER_TYPE_DEFAULT = 0;
 
     /**
@@ -3264,6 +3285,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int DEVICE_OWNER_TYPE_FINANCED = 1;
 
     /**
@@ -14909,10 +14931,14 @@
                     mService.setSsidAllowlist(new ArrayList<>());
                 } else {
                     int policyType = policy.getPolicyType();
+                    List<String> ssidList = new ArrayList<>();
+                    for (WifiSsid ssid : policy.getSsids()) {
+                        ssidList.add(new String(ssid.getBytes(), StandardCharsets.UTF_8));
+                    }
                     if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST) {
-                        mService.setSsidAllowlist(new ArrayList<>(policy.getSsids()));
+                        mService.setSsidAllowlist(ssidList);
                     } else {
-                        mService.setSsidDenylist(new ArrayList<>(policy.getSsids()));
+                        mService.setSsidDenylist(ssidList);
                     }
                 }
             } catch (RemoteException e) {
@@ -14938,11 +14964,21 @@
         try {
             List<String> allowlist = mService.getSsidAllowlist();
             if (!allowlist.isEmpty()) {
-                return WifiSsidPolicy.createAllowlistPolicy(new ArraySet<>(allowlist));
+                List<WifiSsid> wifiSsidAllowlist = new ArrayList<>();
+                for (String ssid : allowlist) {
+                    wifiSsidAllowlist.add(
+                            WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)));
+                }
+                return WifiSsidPolicy.createAllowlistPolicy(new ArraySet<>(wifiSsidAllowlist));
             }
             List<String> denylist = mService.getSsidDenylist();
             if (!denylist.isEmpty()) {
-                return WifiSsidPolicy.createDenylistPolicy(new ArraySet<>(denylist));
+                List<WifiSsid> wifiSsidDenylist = new ArrayList<>();
+                for (String ssid : denylist) {
+                    wifiSsidDenylist.add(
+                            WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)));
+                }
+                return WifiSsidPolicy.createDenylistPolicy(new ArraySet<>(wifiSsidDenylist));
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -15367,4 +15403,45 @@
         }
         return ParcelableResource.loadDefaultString(defaultStringLoader);
     }
+
+    /**
+     * Returns a boolean for whether the DPC has been downloaded during provisioning.
+     *
+     * <p>If true is returned, then any attempts to begin setup again should result in factory reset
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public boolean isDpcDownloaded() {
+        throwIfParentInstance("isDpcDownloaded");
+        if (mService != null) {
+            try {
+                return mService.isDpcDownloaded();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Use to indicate that the DPC has or has not been downloaded during provisioning.
+     *
+     * @param downloaded {@code true} if the dpc has been downloaded during provisioning. false otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public void setDpcDownloaded(boolean downloaded) {
+        throwIfParentInstance("setDpcDownloaded");
+        if (mService != null) {
+            try {
+                mService.setDpcDownloaded(downloaded);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index ac39cb4..7f2e5fd 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -58,6 +58,10 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL;
 import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE;
 import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE;
@@ -512,7 +516,11 @@
             WORK_PROFILE_DEFAULT_APPS_TITLE, HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
             BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE, BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
             BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE, FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
-            LOCATION_AUTO_GRANTED_MESSAGE
+            LOCATION_AUTO_GRANTED_MESSAGE,
+
+            // Dialer Strings
+            NOTIFICATION_INCOMING_WORK_CALL_TITLE, NOTIFICATION_ONGOING_WORK_CALL_TITLE,
+            NOTIFICATION_MISSED_WORK_CALL_TITLE, NOTIFICATION_WIFI_WORK_CALL_LABEL,
     })
     public @interface UpdatableStringId {
     }
@@ -709,6 +717,7 @@
             strings.addAll(DocumentsUi.buildStringsSet());
             strings.addAll(MediaProvider.buildStringsSet());
             strings.addAll(PermissionController.buildStringsSet());
+            strings.addAll(Dialer.buildStringsSet());
             return strings;
         }
 
@@ -2934,5 +2943,54 @@
                 return strings;
             }
         }
+
+        /**
+         * Class containing the identifiers used to update device management-related system strings
+         * in the Dialer app.
+         */
+        public static final class Dialer {
+
+            private Dialer() {
+            }
+
+            private static final String PREFIX = "Dialer.";
+
+            /**
+             * The title of the in-call notification for an incoming work call.
+             */
+            public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+
+            /**
+             * The title of the in-call notification for an ongoing work call.
+             */
+            public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_ONGOING_WORK_CALL_TITLE";
+
+            /**
+             * Missed call notification label, used when there's exactly one missed call from work
+             * contact.
+             */
+            public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
+
+            /**
+             * Label for notification indicating that call is being made over wifi.
+             */
+            public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL =
+                    PREFIX + "NOTIFICATION_WIFI_WORK_CALL_LABEL";
+
+            /**
+             * @hide
+             */
+            static Set<String> buildStringsSet() {
+                Set<String> strings = new HashSet<>();
+                strings.add(NOTIFICATION_INCOMING_WORK_CALL_TITLE);
+                strings.add(NOTIFICATION_ONGOING_WORK_CALL_TITLE);
+                strings.add(NOTIFICATION_MISSED_WORK_CALL_TITLE);
+                strings.add(NOTIFICATION_WIFI_WORK_CALL_LABEL);
+                return strings;
+            }
+        }
     }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a7a51f8..0e1caca 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -555,6 +555,9 @@
     void resetDrawables(in String[] drawableIds);
     ParcelableResource getDrawable(String drawableId, String drawableStyle, String drawableSource);
 
+    boolean isDpcDownloaded();
+    void setDpcDownloaded(boolean downloaded);
+
     void setStrings(in List<DevicePolicyStringResource> strings);
     void resetStrings(in String[] stringIds);
     ParcelableResource getString(String stringId);
diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java
index 3715017..a7046d4 100644
--- a/core/java/android/app/admin/WifiSsidPolicy.java
+++ b/core/java/android/app/admin/WifiSsidPolicy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.net.wifi.WifiSsid;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -70,25 +71,25 @@
     public @interface WifiSsidPolicyType {}
 
     private @WifiSsidPolicyType int mPolicyType;
-    private ArraySet<String> mSsids;
+    private ArraySet<WifiSsid> mSsids;
 
-    private WifiSsidPolicy(@WifiSsidPolicyType int policyType, @NonNull Set<String> ssids) {
+    private WifiSsidPolicy(@WifiSsidPolicyType int policyType, @NonNull Set<WifiSsid> ssids) {
         mPolicyType = policyType;
         mSsids = new ArraySet<>(ssids);
     }
 
     private WifiSsidPolicy(Parcel in) {
         mPolicyType = in.readInt();
-        mSsids = (ArraySet<String>) in.readArraySet(null);
+        mSsids = (ArraySet<WifiSsid>) in.readArraySet(null);
     }
     /**
      * Create the allowlist Wi-Fi SSID Policy.
      *
-     * @param ssids allowlist of SSIDs in UTF-8 without double quotes format
+     * @param ssids allowlist of {@link WifiSsid}
      * @throws IllegalArgumentException if the input ssids list is empty
      */
     @NonNull
-    public static WifiSsidPolicy createAllowlistPolicy(@NonNull Set<String> ssids) {
+    public static WifiSsidPolicy createAllowlistPolicy(@NonNull Set<WifiSsid> ssids) {
         if (ssids.isEmpty()) {
             throw new IllegalArgumentException("SSID list cannot be empty");
         }
@@ -98,11 +99,11 @@
     /**
      * Create the denylist Wi-Fi SSID Policy.
      *
-     * @param ssids denylist of SSIDs in UTF-8 without double quotes format
+     * @param ssids denylist of {@link WifiSsid}
      * @throws IllegalArgumentException if the input ssids list is empty
      */
     @NonNull
-    public static WifiSsidPolicy createDenylistPolicy(@NonNull Set<String> ssids) {
+    public static WifiSsidPolicy createDenylistPolicy(@NonNull Set<WifiSsid> ssids) {
         if (ssids.isEmpty()) {
             throw new IllegalArgumentException("SSID list cannot be empty");
         }
@@ -110,10 +111,10 @@
     }
 
     /**
-     * Returns the set of SSIDs in UTF-8 without double quotes format.
+     * Returns the set of {@link WifiSsid}
      */
     @NonNull
-    public Set<String> getSsids() {
+    public Set<WifiSsid> getSsids() {
         return mSsids;
     }
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6ffea3f..2074125 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6504,15 +6504,26 @@
      * <li>Each permission in {@code permissions} must be a runtime permission.
      * </ul>
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. The revocation happens asynchronously and kills all processes running in the
-     * calling UID. It will be triggered once it is safe to do so. In particular, it will not be
-     * triggered as long as the package remains in the foreground, or has any active manifest
-     * components (e.g. when another app is accessing a content provider in the package).
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * The revocation happens asynchronously and kills all processes running in the calling UID. It
+     * will be triggered once it is safe to do so. In particular, it will not be triggered as long
+     * as the package remains in the foreground, or has any active manifest components (e.g. when
+     * another app is accessing a content provider in the package).
      * <p>
      * If you want to revoke the permissions right away, you could call {@code System.exit()}, but
      * this could affect other apps that are accessing your app at the moment. For example, apps
      * accessing a content provider in your app will all crash.
+     * <p>
+     * Note that the settings UI shows a permission group as granted as long as at least one
+     * permission in the group is granted. If you want the user to observe the revocation in the
+     * settings, you should revoke every permission in the target group. To learn the current list
+     * of permissions in a group, you may use
+     * {@link PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)} and
+     * {@link PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)}. This list
+     * of permissions may evolve over time, so it is recommended to check whether it contains any
+     * permission you wish to retain before trying to revoke an entire group.
      *
      * @param permissions Collection of permissions to be revoked.
      * @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3e527f8..28bef56 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5576,6 +5576,7 @@
     /**
      * A String[] holding attribution tags when used with
      * {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and ACTION_MANAGE_PERMISSION_USAGE
      *
      * E.g. an attribution tag could be location_provider, com.google.android.gms.*, etc.
      */
@@ -5584,17 +5585,20 @@
     /**
      * A long representing the start timestamp (epoch time in millis) of the permission usage
      * when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and ACTION_MANAGE_PERMISSION_USAGE
      */
     public static final String EXTRA_START_TIME = "android.intent.extra.START_TIME";
 
     /**
      * A long representing the end timestamp (epoch time in millis) of the permission usage when
      * used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and ACTION_MANAGE_PERMISSION_USAGE
      */
     public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
 
     /**
-     * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD},
+     * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and {@link #ACTION_MANAGE_PERMISSION_USAGE},
      * that specifies whether the permission usage system UI is showing attribution information
      * for the chosen entry.
      *
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 07227c5..e9466e9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3326,7 +3326,8 @@
      * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio";
+    public static final String FEATURE_TELEPHONY_RADIO_ACCESS =
+            "android.hardware.telephony.radio.access";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 2920e67..87553d8 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -30,9 +30,11 @@
 import android.os.Handler;
 import android.os.ConditionVariable;
 import android.util.Range;
+import android.util.Log;
 import android.view.Surface;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -56,6 +58,7 @@
     private final CameraCharacteristics mCharacteristics;
     private final CameraCaptureSessionImpl mSessionImpl;
     private final ConditionVariable mInitialized = new ConditionVariable();
+    private final String TAG = "CameraConstrainedHighSpeedCaptureSessionImpl";
 
     /**
      * Create a new CameraCaptureSession.
@@ -95,10 +98,33 @@
         StreamConfigurationMap config = mCharacteristics.get(ck);
         SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config);
 
-        // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize
-        // the preview frame rate, should use maxBatch size for that high speed stream
-        // configuration. We choose the former for now.
-        int requestListSize = fpsRange.getUpper() / 30;
+        // Check the high speed video fps ranges for video size and find the min value from the list
+        // and assign it to previewFps which will be used to calculate the requestList size.
+        Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRangesFor(
+                SurfaceUtils.getSurfaceSize(outputSurfaces.iterator().next()));
+        Log.v(TAG, "High speed fps ranges: " + Arrays.toString(highSpeedFpsRanges));
+        int previewFps = Integer.MAX_VALUE;
+        for (Range<Integer> range : highSpeedFpsRanges) {
+            int rangeMin = range.getLower();
+            if (previewFps > rangeMin) {
+                previewFps = rangeMin;
+            }
+        }
+        // Since we only want to support 60fps apart from 30fps, if the min value is not 60,
+        // then continue to calculate the requestList size using value 30.
+        if (previewFps != 60 && previewFps != 30) {
+            Log.w(TAG, "previewFps is neither 60 nor 30.");
+            previewFps = 30;
+        }
+        Log.v(TAG, "previewFps: " + previewFps);
+
+        int requestListSize = fpsRange.getUpper() / previewFps;
+        // If it's a preview, keep requestList size fixed = 1.
+        if (fpsRange.getUpper() > fpsRange.getLower()) {
+            requestListSize = 1;
+        }
+
+        Log.v(TAG, "Request list size is: " + requestListSize);
         List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
 
         // Prepare the Request builders: need carry over the request controls.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fc2fbc3..223b8cc 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,7 +346,7 @@
      */
     @AnyThread
     public static boolean canImeRenderGesturalNavButtons() {
-        return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
+        return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
     }
 
     /**
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index e5c22e4..83fc727 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -546,7 +546,8 @@
         public String toDebugString() {
             return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
                     + " mNavigationBarFrame=" + mNavigationBarFrame
-                    + " mShouldShowImeSwitcherWhenImeIsShown" + mShouldShowImeSwitcherWhenImeIsShown
+                    + " mShouldShowImeSwitcherWhenImeIsShown="
+                    + mShouldShowImeSwitcherWhenImeIsShown
                     + " mAppearance=0x" + Integer.toHexString(mAppearance)
                     + " mDarkIntensity=" + mDarkIntensity
                     + " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index d9c9a2b..bc7fb78 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -63,7 +63,7 @@
     boolean isUserTypeEnabled(in String userType);
     boolean canAddMoreUsersOfType(in String userType);
     int getRemainingCreatableUserCount(in String userType);
-    int getRemainingCreatableProfileCount(in String userType, int userId, boolean allowedToRemoveOne);
+    int getRemainingCreatableProfileCount(in String userType, int userId);
     boolean canAddMoreProfilesToUser(in String userType, int userId, boolean allowedToRemoveOne);
     boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
     UserInfo getProfileParent(int userId);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7b8d34b..2bd1dbb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4055,9 +4055,6 @@
      * <p>Note that is applicable to any profile type (currently not including Restricted profiles).
      *
      * @param userType the type of profile, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}.
-     * @param allowedToRemoveOne whether removing an existing profile of given type -if there is-
-     *                           from the context user to make up space should be taken into account
-     *                           for the calculation.
      * @return how many additional profiles can be created.
      * @hide
      */
@@ -4068,13 +4065,11 @@
             android.Manifest.permission.QUERY_USERS
     })
     @UserHandleAware
-    public int getRemainingCreatableProfileCount(@NonNull String userType,
-            boolean allowedToRemoveOne) {
+    public int getRemainingCreatableProfileCount(@NonNull String userType) {
         Objects.requireNonNull(userType, "userType must not be null");
         try {
             // TODO(b/142482943): Perhaps let the following code apply to restricted users too.
-            return mService.getRemainingCreatableProfileCount(userType, mUserId,
-                    allowedToRemoveOne);
+            return mService.getRemainingCreatableProfileCount(userType, mUserId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 1c0320e..619c870 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -79,7 +79,8 @@
     void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
 
     void startOneTimePermissionSession(String packageName, int userId, long timeout,
-            int importanceToResetTimer, int importanceToKeepSessionAlive);
+            long revokeAfterKilledDelay, int importanceToResetTimer,
+            int importanceToKeepSessionAlive);
 
     void stopOneTimePermissionSession(String packageName, int userId);
 
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 0cf06aa..a005ab4e 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -907,21 +907,23 @@
      * <li>Each permission in {@code permissions} must be a runtime permission.
      * </ul>
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. This revocation happens asynchronously and kills all processes running in the
-     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * This revocation happens asynchronously and kills all processes running in the same UID as
+     * {@code packageName}. It will be triggered once it is safe to do so.
      *
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
-     * @param callback Callback called when the revocation request has been completed.
      *
-     * @see Context#revokeOwnPermissionsOnKill(Collection)
+     * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
      *
      * @hide
      */
     public void revokeOwnPermissionsOnKill(@NonNull String packageName,
-            @NonNull List<String> permissions, AndroidFuture<Void> callback) {
+            @NonNull List<String> permissions) {
         mRemoteService.postAsync(service -> {
+            AndroidFuture<Void> callback = new AndroidFuture<>();
             service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
             return callback;
         }).whenComplete((result, err) -> {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 8d9f82b..3292e711 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -291,7 +291,7 @@
 
     /**
      * Called when a package is considered inactive based on the criteria given by
-     * {@link PermissionManager#startOneTimePermissionSession(String, long, int, int)}.
+     * {@link PermissionManager#startOneTimePermissionSession(String, long, long, int, int)}.
      * This method is called at the end of a one-time permission session
      *
      * @param packageName The package that has been inactive
@@ -329,9 +329,11 @@
      * Triggers the revocation of one or more permissions for a package. This should only be called
      * at the request of {@code packageName}.
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. This revocation happens asynchronously and kills all processes running in the
-     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * This revocation happens asynchronously and kills all processes running in the same UID as
+     * {@code packageName}. It will be triggered once it is safe to do so.
      *
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 15f13eb..12fa0dd 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -20,6 +20,7 @@
 
 import android.Manifest;
 import android.annotation.CheckResult;
+import android.annotation.DurationMillisLong;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1282,6 +1283,22 @@
     }
 
     /**
+     * Starts a one-time permission session for a given package.
+     * @see #startOneTimePermissionSession(String, long, long, int, int)
+     * @hide
+     * @deprecated Use {@link #startOneTimePermissionSession(String, long, long, int, int)} instead
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
+    public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+            @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
+            @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
+        startOneTimePermissionSession(packageName, timeoutMillis, -1,
+                importanceToResetTimer, importanceToKeepSessionAlive);
+    }
+
+    /**
      * Starts a one-time permission session for a given package. A one-time permission session is
      * ended if app becomes inactive. Inactivity is defined as the package's uid importance level
      * staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid
@@ -1301,25 +1318,33 @@
      * {@link PermissionControllerService#onOneTimePermissionSessionTimeout(String)} is invoked.
      * </p>
      * <p>
-     * Note that if there is currently an active session for a package a new one isn't created and
-     * the existing one isn't changed.
+     * Note that if there is currently an active session for a package a new one isn't created but
+     * each parameter of the existing one will be updated to the more aggressive of both sessions.
+     * This means that durations will be set to the shortest parameter and importances will be set
+     * to the lowest one.
      * </p>
      * @param packageName The package to start a one-time permission session for
      * @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+     * @param revokeAfterKilledDelayMillis Number of milliseconds to wait before revoking on the
+     *                                     event an app is terminated. Set to -1 to use default
+     *                                     value for the device.
      * @param importanceToResetTimer The least important level to uid must be to reset the timer
      * @param importanceToKeepSessionAlive The least important level the uid must be to keep the
-     *                                    session alive
+     *                                     session alive
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
-    public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+    public void startOneTimePermissionSession(@NonNull String packageName,
+            @DurationMillisLong long timeoutMillis,
+            @DurationMillisLong long revokeAfterKilledDelayMillis,
             @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
             @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
         try {
             mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(),
-                    timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+                    timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
+                    importanceToKeepSessionAlive);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 34e35d4..3ff0161 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1425,25 +1425,6 @@
         public static final String KEY_TYPE = "key_type";
 
         /**
-         * MVNO type:
-         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
-         * <P> Type: TEXT </P>
-         */
-        public static final String MVNO_TYPE = "mvno_type";
-
-        /**
-         * MVNO data.
-         * Use the following examples.
-         * <ul>
-         *     <li>SPN: A MOBILE, BEN NL, ...</li>
-         *     <li>IMSI: 302720x94, 2060188, ...</li>
-         *     <li>GID: 4E, 33, ...</li>
-         * </ul>
-         * <P> Type: TEXT </P>
-         */
-        public static final String MVNO_MATCH_DATA = "mvno_match_data";
-
-        /**
          * The carrier public key that is used for the IMSI encryption.
          * <P> Type: TEXT </P>
          */
@@ -1470,6 +1451,11 @@
         public static final String LAST_MODIFIED = "last_modified";
 
         /**
+         * Carrier ID of the operetor.
+         * <P> Type: TEXT </P>
+         */
+        public static final String CARRIER_ID = "carrier_id";
+        /**
          * The {@code content://} style URL for this table.
          */
         @NonNull
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index e33f180..468e087c 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -20,15 +20,23 @@
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.app.ActivityTaskManager;
+import android.app.Instrumentation;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
@@ -41,6 +49,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -120,6 +129,7 @@
     private LifecycleState mLifecycleState = LifecycleState.INITIALIZED;
     private boolean mAreTransientInsetsVisibleDueToGesture = false;
     private IGameSessionController mGameSessionController;
+    private Context mContext;
     private int mTaskId;
     private GameSessionRootView mGameSessionRootView;
     private SurfaceControlViewHost mSurfaceControlViewHost;
@@ -137,6 +147,7 @@
             int heightPx) {
         mGameSessionController = gameSessionController;
         mTaskId = taskId;
+        mContext = context;
         mSurfaceControlViewHost = surfaceControlViewHost;
         mGameSessionRootView = new GameSessionRootView(context, mSurfaceControlViewHost);
         surfaceControlViewHost.setView(mGameSessionRootView, widthPx, heightPx);
@@ -299,6 +310,8 @@
      * {@code View} may not be cleared once set, but may be replaced by invoking
      * {@link #setTaskOverlayView(View, ViewGroup.LayoutParams)} again.
      *
+     * <p><b>WARNING</b>: Callers <b>must</b> ensure that only trusted views are provided.
+     *
      * @param view         The desired content to display.
      * @param layoutParams Layout parameters for the view.
      */
@@ -456,4 +469,67 @@
                 break;
         }
     }
+
+    /**
+     * Launches an activity within the same activity stack as the {@link GameSession}. When the
+     * target activity exits, {@link GameSessionActivityCallback#onActivityResult(int, Intent)} will
+     * be invoked with the result code and result data directly from the target activity (in other
+     * words, the result code and data set via the target activity's
+     * {@link android.app.Activity#startActivityForResult} call). The caller is expected to handle
+     * the results that the target activity returns.
+     *
+     * <p>Any activity that an app would normally be able to start via {@link
+     * android.app.Activity#startActivityForResult} will be startable via this method.
+     *
+     * <p>Started activities may see a different calling package than the game session's package
+     * when calling {@link android.app.Activity#getCallingPackage()}.
+     *
+     * <p> If an exception is thrown while handling {@code intent},
+     * {@link GameSessionActivityCallback#onActivityStartFailed(Throwable)} will be called instead
+     * of {@link GameSessionActivityCallback#onActivityResult(int, Intent)}.
+     *
+     * @param intent   The intent to start.
+     * @param options  Additional options for how the Activity should be started. See
+     *                 {@link android.app.Activity#startActivityForResult(Intent, int, Bundle)} for
+     *                 more details. This value may be null.
+     * @param executor Executor on which {@code callback} should be invoked.
+     * @param callback Callback to be invoked once the started activity has finished.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
+    public final void startActivityFromGameSessionForResult(
+            @NonNull Intent intent, @Nullable Bundle options, @NonNull Executor executor,
+            @NonNull GameSessionActivityCallback callback) {
+        Objects.requireNonNull(intent);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        AndroidFuture<GameSessionActivityResult> future =
+                new AndroidFuture<GameSessionActivityResult>()
+                        .whenCompleteAsync((result, ex) -> {
+                            if (ex != null) {
+                                callback.onActivityStartFailed(ex);
+                                return;
+                            }
+                            callback.onActivityResult(result.getResultCode(), result.getData());
+                        }, executor);
+
+        final Intent trampolineIntent = new Intent();
+        trampolineIntent.setComponent(
+                new ComponentName(
+                        "android", "android.service.games.GameSessionTrampolineActivity"));
+        trampolineIntent.putExtra(GameSessionTrampolineActivity.INTENT_KEY, intent);
+        trampolineIntent.putExtra(GameSessionTrampolineActivity.OPTIONS_KEY, options);
+        trampolineIntent.putExtra(
+                GameSessionTrampolineActivity.FUTURE_KEY, future);
+
+        try {
+            int result = ActivityTaskManager.getService().startActivityFromGameSession(
+                    mContext.getIApplicationThread(), mContext.getPackageName(), "GameSession",
+                    Binder.getCallingPid(), Binder.getCallingUid(), trampolineIntent, mTaskId,
+                    UserHandle.myUserId());
+            Instrumentation.checkStartActivityResult(result, trampolineIntent);
+        } catch (Throwable t) {
+            executor.execute(() -> callback.onActivityStartFailed(t));
+        }
+    }
 }
diff --git a/core/java/android/service/games/GameSessionActivityCallback.java b/core/java/android/service/games/GameSessionActivityCallback.java
new file mode 100644
index 0000000..3b11df1
--- /dev/null
+++ b/core/java/android/service/games/GameSessionActivityCallback.java
@@ -0,0 +1,54 @@
+/*
+ * 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.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Callback invoked when an activity launched via
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)}} has returned a result or failed to start.
+ *
+ * @hide
+ */
+@SystemApi
+public interface GameSessionActivityCallback {
+    /**
+     * Callback invoked when an activity launched via
+     * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+     * GameSessionActivityCallback)}} has returned a result.
+     *
+     * @param resultCode The result code of the launched activity. See {@link
+     *                   android.app.Activity#setResult(int)}.
+     * @param data       Any data returned by the launched activity. See {@link
+     *                   android.app.Activity#setResult(int, Intent)}.
+     */
+    void onActivityResult(int resultCode, @Nullable Intent data);
+
+    /**
+     * Callback invoked when a throwable was thrown when launching the {@link Intent} in
+     * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+     * GameSessionActivityCallback)}}.
+     */
+    default void onActivityStartFailed(@NonNull Throwable t) {}
+}
diff --git a/core/java/android/service/games/GameSessionActivityResult.java b/core/java/android/service/games/GameSessionActivityResult.java
new file mode 100644
index 0000000..a2ec6ad
--- /dev/null
+++ b/core/java/android/service/games/GameSessionActivityResult.java
@@ -0,0 +1,71 @@
+/*
+ * 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.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+final class GameSessionActivityResult implements Parcelable {
+
+    public static final Creator<GameSessionActivityResult> CREATOR =
+            new Creator<GameSessionActivityResult>() {
+                @Override
+                public GameSessionActivityResult createFromParcel(Parcel in) {
+                    int resultCode = in.readInt();
+                    Intent data = in.readParcelable(Intent.class.getClassLoader(), Intent.class);
+                    return new GameSessionActivityResult(resultCode, data);
+                }
+
+                @Override
+                public GameSessionActivityResult[] newArray(int size) {
+                    return new GameSessionActivityResult[size];
+                }
+            };
+
+    private final int mResultCode;
+    @Nullable
+    private final Intent mData;
+
+    GameSessionActivityResult(int resultCode, @Nullable Intent data) {
+        mResultCode = resultCode;
+        mData = data;
+    }
+
+    int getResultCode() {
+        return mResultCode;
+    }
+
+    @Nullable
+    Intent getData() {
+        return mData;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mResultCode);
+        dest.writeParcelable(mData, flags);
+    }
+}
diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java
new file mode 100644
index 0000000..ddea098
--- /dev/null
+++ b/core/java/android/service/games/GameSessionTrampolineActivity.java
@@ -0,0 +1,79 @@
+/*
+ * 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.service.games;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Trampoline activity that enables the
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)} API by reusing existing activity result infrastructure in the
+ * {@link Activity} class. This activity forwards activity results back to the calling
+ * {@link GameSession} via {@link AndroidFuture}.
+ *
+ * @hide
+ */
+public final class GameSessionTrampolineActivity extends Activity {
+    private static final String TAG = "GameSessionTrampoline";
+    private static final int REQUEST_CODE = 1;
+
+    static final String FUTURE_KEY = "GameSessionTrampolineActivity.future";
+    static final String INTENT_KEY = "GameSessionTrampolineActivity.intent";
+    static final String OPTIONS_KEY = "GameSessionTrampolineActivity.options";
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        try {
+            startActivityAsCaller(
+                    getIntent().getParcelableExtra(INTENT_KEY),
+                    getIntent().getBundleExtra(OPTIONS_KEY),
+                    null,
+                    false,
+                    getUserId(),
+                    REQUEST_CODE);
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to launch activity from game session");
+            AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
+                    FUTURE_KEY);
+            future.completeExceptionally(e);
+            finish();
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode != REQUEST_CODE) {
+            // Something went very wrong if we hit this code path, and we should bail.
+            throw new IllegalStateException("Unexpected request code: " + requestCode);
+        }
+
+        AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
+                FUTURE_KEY);
+        future.complete(new GameSessionActivityResult(resultCode, data));
+        finish();
+    }
+}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index a427ab8..cd8dd86 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -553,8 +553,20 @@
     public static final int TYPE_ASSIST_READING_CONTEXT = 0x01000000;
 
     /**
-     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
-     * The type of change is not defined.
+     * Represents a change in the speech state defined by the content-change types. A change in the
+     * speech state occurs when another service is either speaking or listening for human speech.
+     * This event helps avoid conflicts where two services want to speak or one listens
+     * when another speaks.
+     * @see #SPEECH_STATE_SPEAKING_START
+     * @see #SPEECH_STATE_SPEAKING_END
+     * @see #SPEECH_STATE_LISTENING_START
+     * @see #SPEECH_STATE_LISTENING_END
+     */
+    public static final int TYPE_SPEECH_STATE_CHANGE = 0x02000000;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: The type of change is not
+     * defined.
      */
     public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000;
 
@@ -641,6 +653,27 @@
      */
     public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200;
 
+    /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */
+    public static final int SPEECH_STATE_SPEAKING_START = 0x00000001;
+
+    /**
+     * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is no longer
+     * speaking.
+     */
+    public static final int SPEECH_STATE_SPEAKING_END = 0x00000002;
+
+    /**
+     * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is listening to the
+     * microphone.
+     */
+    public static final int SPEECH_STATE_LISTENING_START = 0x00000004;
+
+    /**
+     * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is no longer
+     * listening to the microphone.
+     */
+    public static final int SPEECH_STATE_LISTENING_END = 0x00000008;
+
     /**
      * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
      * The window was added.
@@ -730,50 +763,69 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = { "CONTENT_CHANGE_TYPE_" },
+    @IntDef(
+            flag = true,
+            prefix = {"CONTENT_CHANGE_TYPE_"},
             value = {
-                    CONTENT_CHANGE_TYPE_UNDEFINED,
-                    CONTENT_CHANGE_TYPE_SUBTREE,
-                    CONTENT_CHANGE_TYPE_TEXT,
-                    CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION,
-                    CONTENT_CHANGE_TYPE_STATE_DESCRIPTION,
-                    CONTENT_CHANGE_TYPE_PANE_TITLE,
-                    CONTENT_CHANGE_TYPE_PANE_APPEARED,
-                    CONTENT_CHANGE_TYPE_PANE_DISAPPEARED,
-                    CONTENT_CHANGE_TYPE_DRAG_STARTED,
-                    CONTENT_CHANGE_TYPE_DRAG_DROPPED,
-                    CONTENT_CHANGE_TYPE_DRAG_CANCELLED
+                CONTENT_CHANGE_TYPE_UNDEFINED,
+                CONTENT_CHANGE_TYPE_SUBTREE,
+                CONTENT_CHANGE_TYPE_TEXT,
+                CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION,
+                CONTENT_CHANGE_TYPE_STATE_DESCRIPTION,
+                CONTENT_CHANGE_TYPE_PANE_TITLE,
+                CONTENT_CHANGE_TYPE_PANE_APPEARED,
+                CONTENT_CHANGE_TYPE_PANE_DISAPPEARED,
+                CONTENT_CHANGE_TYPE_DRAG_STARTED,
+                CONTENT_CHANGE_TYPE_DRAG_DROPPED,
+                CONTENT_CHANGE_TYPE_DRAG_CANCELLED,
             })
     public @interface ContentChangeTypes {}
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "TYPE_" }, value = {
-            TYPE_VIEW_CLICKED,
-            TYPE_VIEW_LONG_CLICKED,
-            TYPE_VIEW_SELECTED,
-            TYPE_VIEW_FOCUSED,
-            TYPE_VIEW_TEXT_CHANGED,
-            TYPE_WINDOW_STATE_CHANGED,
-            TYPE_NOTIFICATION_STATE_CHANGED,
-            TYPE_VIEW_HOVER_ENTER,
-            TYPE_VIEW_HOVER_EXIT,
-            TYPE_TOUCH_EXPLORATION_GESTURE_START,
-            TYPE_TOUCH_EXPLORATION_GESTURE_END,
-            TYPE_WINDOW_CONTENT_CHANGED,
-            TYPE_VIEW_SCROLLED,
-            TYPE_VIEW_TEXT_SELECTION_CHANGED,
-            TYPE_ANNOUNCEMENT,
-            TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-            TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
-            TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
-            TYPE_GESTURE_DETECTION_START,
-            TYPE_GESTURE_DETECTION_END,
-            TYPE_TOUCH_INTERACTION_START,
-            TYPE_TOUCH_INTERACTION_END,
-            TYPE_WINDOWS_CHANGED,
-            TYPE_VIEW_CONTEXT_CLICKED,
-            TYPE_ASSIST_READING_CONTEXT
-    })
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            flag = true,
+            prefix = {"SPEECH_STATE_"},
+            value = {
+                SPEECH_STATE_SPEAKING_START,
+                SPEECH_STATE_SPEAKING_END,
+                SPEECH_STATE_LISTENING_START,
+                SPEECH_STATE_LISTENING_END
+            })
+    public @interface SpeechStateChangeTypes {}
+
+    /** @hide */
+    @IntDef(
+            flag = true,
+            prefix = {"TYPE_"},
+            value = {
+                TYPE_VIEW_CLICKED,
+                TYPE_VIEW_LONG_CLICKED,
+                TYPE_VIEW_SELECTED,
+                TYPE_VIEW_FOCUSED,
+                TYPE_VIEW_TEXT_CHANGED,
+                TYPE_WINDOW_STATE_CHANGED,
+                TYPE_NOTIFICATION_STATE_CHANGED,
+                TYPE_VIEW_HOVER_ENTER,
+                TYPE_VIEW_HOVER_EXIT,
+                TYPE_TOUCH_EXPLORATION_GESTURE_START,
+                TYPE_TOUCH_EXPLORATION_GESTURE_END,
+                TYPE_WINDOW_CONTENT_CHANGED,
+                TYPE_VIEW_SCROLLED,
+                TYPE_VIEW_TEXT_SELECTION_CHANGED,
+                TYPE_ANNOUNCEMENT,
+                TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+                TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+                TYPE_GESTURE_DETECTION_START,
+                TYPE_GESTURE_DETECTION_END,
+                TYPE_TOUCH_INTERACTION_START,
+                TYPE_TOUCH_INTERACTION_END,
+                TYPE_WINDOWS_CHANGED,
+                TYPE_VIEW_CONTEXT_CLICKED,
+                TYPE_ASSIST_READING_CONTEXT,
+                TYPE_SPEECH_STATE_CHANGE
+            })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
 
@@ -814,6 +866,7 @@
     int mAction;
     int mContentChangeTypes;
     int mWindowChangeTypes;
+    int mSpeechStateChangeTypes;
 
     /**
      * The stack trace describing where this event originated from on the app side.
@@ -867,6 +920,7 @@
         mMovementGranularity = event.mMovementGranularity;
         mAction = event.mAction;
         mContentChangeTypes = event.mContentChangeTypes;
+        mSpeechStateChangeTypes = event.mSpeechStateChangeTypes;
         mWindowChangeTypes = event.mWindowChangeTypes;
         mEventTime = event.mEventTime;
         mPackageName = event.mPackageName;
@@ -1008,6 +1062,51 @@
     }
 
     /**
+     * Gets the speech state signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event
+     *
+     * @see #SPEECH_STATE_SPEAKING_START
+     * @see #SPEECH_STATE_SPEAKING_END
+     * @see #SPEECH_STATE_LISTENING_START
+     * @see #SPEECH_STATE_LISTENING_END
+     */
+    public int getSpeechStateChangeTypes() {
+        return mSpeechStateChangeTypes;
+    }
+
+    private static String speechStateChangedTypesToString(int types) {
+        return BitUtils.flagsToString(
+                types, AccessibilityEvent::singleSpeechStateChangeTypeToString);
+    }
+
+    private static String singleSpeechStateChangeTypeToString(int type) {
+        switch (type) {
+            case SPEECH_STATE_SPEAKING_START:
+                return "SPEECH_STATE_SPEAKING_START";
+            case SPEECH_STATE_LISTENING_START:
+                return "SPEECH_STATE_LISTENING_START";
+            case SPEECH_STATE_SPEAKING_END:
+                return "SPEECH_STATE_SPEAKING_END";
+            case SPEECH_STATE_LISTENING_END:
+                return "SPEECH_STATE_LISTENING_END";
+            default:
+                return Integer.toHexString(type);
+        }
+    }
+
+    /**
+     * Sets the speech state type signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event
+     *
+     * @see #SPEECH_STATE_SPEAKING_START
+     * @see #SPEECH_STATE_SPEAKING_END
+     * @see #SPEECH_STATE_LISTENING_START
+     * @see #SPEECH_STATE_LISTENING_END
+     */
+    public void setSpeechStateChangeTypes(int state) {
+        enforceNotSealed();
+        mSpeechStateChangeTypes = state;
+    }
+
+    /**
      * Get the bit mask of change types signaled by a {@link #TYPE_WINDOWS_CHANGED} event. A
      * single event may represent multiple change types.
      *
@@ -1239,6 +1338,7 @@
         mAction = 0;
         mContentChangeTypes = 0;
         mWindowChangeTypes = 0;
+        mSpeechStateChangeTypes = 0;
         mPackageName = null;
         mEventTime = 0;
         if (mRecords != null) {
@@ -1261,6 +1361,7 @@
         mAction = parcel.readInt();
         mContentChangeTypes = parcel.readInt();
         mWindowChangeTypes = parcel.readInt();
+        mSpeechStateChangeTypes = parcel.readInt();
         mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         mEventTime = parcel.readLong();
         mConnectionId = parcel.readInt();
@@ -1332,6 +1433,7 @@
         parcel.writeInt(mAction);
         parcel.writeInt(mContentChangeTypes);
         parcel.writeInt(mWindowChangeTypes);
+        parcel.writeInt(mSpeechStateChangeTypes);
         TextUtils.writeToParcel(mPackageName, parcel, 0);
         parcel.writeLong(mEventTime);
         parcel.writeInt(mConnectionId);
@@ -1500,6 +1602,7 @@
             case TYPE_WINDOWS_CHANGED: return "TYPE_WINDOWS_CHANGED";
             case TYPE_VIEW_CONTEXT_CLICKED: return "TYPE_VIEW_CONTEXT_CLICKED";
             case TYPE_ASSIST_READING_CONTEXT: return "TYPE_ASSIST_READING_CONTEXT";
+            case TYPE_SPEECH_STATE_CHANGE: return "TYPE_SPEECH_STATE_CHANGE";
             default: return Integer.toHexString(eventType);
         }
     }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 3914a3c..fadbdbb 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -1251,18 +1251,19 @@
         public float value;
 
         /**
-         * Size descriptions can appear inthree forms:
+         * Size descriptions can appear in four forms:
          * <ol>
          * <li>An absolute size. This is represented by a number.</li>
          * <li>A size relative to the size of the object being animated. This
-         * is represented by a number followed by "%".</li> *
+         * is represented by a number followed by "%".</li>
          * <li>A size relative to the size of the parent of object being
          * animated. This is represented by a number followed by "%p".</li>
+         * <li>(Starting from API 32) A complex number.</li>
          * </ol>
          * @param value The typed value to parse
          * @return The parsed version of the description
          */
-        static Description parseValue(TypedValue value) {
+        static Description parseValue(TypedValue value, Context context) {
             Description d = new Description();
             if (value == null) {
                 d.type = ABSOLUTE;
@@ -1283,6 +1284,11 @@
                     d.type = ABSOLUTE;
                     d.value = value.data;
                     return d;
+                } else if (value.type == TypedValue.TYPE_DIMENSION) {
+                    d.type = ABSOLUTE;
+                    d.value = TypedValue.complexToDimension(value.data,
+                            context.getResources().getDisplayMetrics());
+                    return d;
                 }
             }
 
diff --git a/core/java/android/view/animation/ClipRectAnimation.java b/core/java/android/view/animation/ClipRectAnimation.java
index 21509d3..3f4b3e7 100644
--- a/core/java/android/view/animation/ClipRectAnimation.java
+++ b/core/java/android/view/animation/ClipRectAnimation.java
@@ -20,7 +20,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 
 /**
  * An animation that controls the clip of an object. See the
@@ -66,43 +65,43 @@
                 com.android.internal.R.styleable.ClipRectAnimation);
 
         Description d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromLeft));
+                com.android.internal.R.styleable.ClipRectAnimation_fromLeft), context);
         mFromLeftType = d.type;
         mFromLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromTop));
+                com.android.internal.R.styleable.ClipRectAnimation_fromTop), context);
         mFromTopType = d.type;
         mFromTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromRight));
+                com.android.internal.R.styleable.ClipRectAnimation_fromRight), context);
         mFromRightType = d.type;
         mFromRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromBottom));
+                com.android.internal.R.styleable.ClipRectAnimation_fromBottom), context);
         mFromBottomType = d.type;
         mFromBottomValue = d.value;
 
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toLeft));
+                com.android.internal.R.styleable.ClipRectAnimation_toLeft), context);
         mToLeftType = d.type;
         mToLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toTop));
+                com.android.internal.R.styleable.ClipRectAnimation_toTop), context);
         mToTopType = d.type;
         mToTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toRight));
+                com.android.internal.R.styleable.ClipRectAnimation_toRight), context);
         mToRightType = d.type;
         mToRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toBottom));
+                com.android.internal.R.styleable.ClipRectAnimation_toBottom), context);
         mToBottomType = d.type;
         mToBottomValue = d.value;
 
diff --git a/core/java/android/view/animation/ExtendAnimation.java b/core/java/android/view/animation/ExtendAnimation.java
index fd627e5..210eb8a 100644
--- a/core/java/android/view/animation/ExtendAnimation.java
+++ b/core/java/android/view/animation/ExtendAnimation.java
@@ -63,43 +63,43 @@
                 com.android.internal.R.styleable.ExtendAnimation);
 
         Description d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft), context);
         mFromLeftType = d.type;
         mFromLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendTop));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendTop), context);
         mFromTopType = d.type;
         mFromTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendRight));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendRight), context);
         mFromRightType = d.type;
         mFromRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom), context);
         mFromBottomType = d.type;
         mFromBottomValue = d.value;
 
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendLeft));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendLeft), context);
         mToLeftType = d.type;
         mToLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendTop));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendTop), context);
         mToTopType = d.type;
         mToTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendRight));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendRight), context);
         mToRightType = d.type;
         mToRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendBottom));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendBottom), context);
         mToBottomType = d.type;
         mToBottomValue = d.value;
 
diff --git a/core/java/android/view/animation/GridLayoutAnimationController.java b/core/java/android/view/animation/GridLayoutAnimationController.java
index 0f189ae..c77f54f 100644
--- a/core/java/android/view/animation/GridLayoutAnimationController.java
+++ b/core/java/android/view/animation/GridLayoutAnimationController.java
@@ -116,10 +116,12 @@
                 com.android.internal.R.styleable.GridLayoutAnimation);
 
         Animation.Description d = Animation.Description.parseValue(
-                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay));
+                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay),
+                context);
         mColumnDelay = d.value;
         d = Animation.Description.parseValue(
-                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay));
+                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay),
+                context);
         mRowDelay = d.value;
         //noinspection PointlessBitwiseExpression
         mDirection = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_direction,
diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java
index e2b7519..1d56d29 100644
--- a/core/java/android/view/animation/LayoutAnimationController.java
+++ b/core/java/android/view/animation/LayoutAnimationController.java
@@ -106,7 +106,7 @@
         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LayoutAnimation);
 
         Animation.Description d = Animation.Description.parseValue(
-                a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay));
+                a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay), context);
         mDelay = d.value;
 
         mOrder = a.getInt(com.android.internal.R.styleable.LayoutAnimation_animationOrder, ORDER_NORMAL);
diff --git a/core/java/android/view/animation/RotateAnimation.java b/core/java/android/view/animation/RotateAnimation.java
index 3c325d9..0613cd2 100644
--- a/core/java/android/view/animation/RotateAnimation.java
+++ b/core/java/android/view/animation/RotateAnimation.java
@@ -56,12 +56,12 @@
         mToDegrees = a.getFloat(com.android.internal.R.styleable.RotateAnimation_toDegrees, 0.0f);
 
         Description d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.RotateAnimation_pivotX));
+                com.android.internal.R.styleable.RotateAnimation_pivotX), context);
         mPivotXType = d.type;
         mPivotXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.RotateAnimation_pivotY));
+                com.android.internal.R.styleable.RotateAnimation_pivotY), context);
         mPivotYType = d.type;
         mPivotYValue = d.value;
 
diff --git a/core/java/android/view/animation/ScaleAnimation.java b/core/java/android/view/animation/ScaleAnimation.java
index e9a8436..533ef45 100644
--- a/core/java/android/view/animation/ScaleAnimation.java
+++ b/core/java/android/view/animation/ScaleAnimation.java
@@ -118,12 +118,12 @@
         }
 
         Description d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ScaleAnimation_pivotX));
+                com.android.internal.R.styleable.ScaleAnimation_pivotX), context);
         mPivotXType = d.type;
         mPivotXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.ScaleAnimation_pivotY));
+                com.android.internal.R.styleable.ScaleAnimation_pivotY), context);
         mPivotYType = d.type;
         mPivotYValue = d.value;
 
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index 3365c70..e27469c 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -73,22 +73,22 @@
                 com.android.internal.R.styleable.TranslateAnimation);
 
         Description d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.TranslateAnimation_fromXDelta));
+                com.android.internal.R.styleable.TranslateAnimation_fromXDelta), context);
         mFromXType = d.type;
         mFromXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.TranslateAnimation_toXDelta));
+                com.android.internal.R.styleable.TranslateAnimation_toXDelta), context);
         mToXType = d.type;
         mToXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.TranslateAnimation_fromYDelta));
+                com.android.internal.R.styleable.TranslateAnimation_fromYDelta), context);
         mFromYType = d.type;
         mFromYValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.TranslateAnimation_toYDelta));
+                com.android.internal.R.styleable.TranslateAnimation_toYDelta), context);
         mToYType = d.type;
         mToYValue = d.value;
 
diff --git a/core/java/com/android/internal/app/BlockedAppActivity.java b/core/java/com/android/internal/app/BlockedAppActivity.java
index 65526eb..fbdbbfb 100644
--- a/core/java/com/android/internal/app/BlockedAppActivity.java
+++ b/core/java/com/android/internal/app/BlockedAppActivity.java
@@ -17,7 +17,6 @@
 package com.android.internal.app;
 
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
@@ -36,9 +35,6 @@
     private static final String TAG = "BlockedAppActivity";
     private static final String PACKAGE_NAME = "com.android.internal.app";
     private static final String EXTRA_BLOCKED_PACKAGE = PACKAGE_NAME + ".extra.BLOCKED_PACKAGE";
-    private static final String EXTRA_BLOCKED_ACTIVITY_INFO =
-            PACKAGE_NAME + ".extra.BLOCKED_ACTIVITY_INFO";
-    private static final String EXTRA_STREAMED_DEVICE = PACKAGE_NAME + ".extra.STREAMED_DEVICE";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -52,30 +48,17 @@
             return;
         }
 
-        CharSequence appLabel = null;
         String packageName = intent.getStringExtra(EXTRA_BLOCKED_PACKAGE);
-        ActivityInfo activityInfo = intent.getParcelableExtra(EXTRA_BLOCKED_ACTIVITY_INFO);
-        if (activityInfo != null) {
-            appLabel = activityInfo.loadLabel(getPackageManager());
-        } else if (!TextUtils.isEmpty(packageName)) {
-            appLabel = getAppLabel(userId, packageName);
-        }
-
-        if (TextUtils.isEmpty(appLabel)) {
-            Slog.wtf(TAG, "Invalid package: " + packageName + " or activity info: " + activityInfo);
+        if (TextUtils.isEmpty(packageName)) {
+            Slog.wtf(TAG, "Invalid package: " + packageName);
             finish();
             return;
         }
 
-        CharSequence streamedDeviceName = intent.getCharSequenceExtra(EXTRA_STREAMED_DEVICE);
-        if (!TextUtils.isEmpty(streamedDeviceName)) {
-            mAlertParams.mTitle = getString(R.string.app_streaming_blocked_title, appLabel);
-            mAlertParams.mMessage =
-                    getString(R.string.app_streaming_blocked_message, streamedDeviceName);
-        } else {
-            mAlertParams.mTitle = getString(R.string.app_blocked_title);
-            mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
-        }
+        CharSequence appLabel = getAppLabel(userId, packageName);
+
+        mAlertParams.mTitle = getString(R.string.app_blocked_title);
+        mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
         mAlertParams.mPositiveButtonText = getString(android.R.string.ok);
         setupAlert();
     }
@@ -100,19 +83,4 @@
                 .putExtra(Intent.EXTRA_USER_ID, userId)
                 .putExtra(EXTRA_BLOCKED_PACKAGE, packageName);
     }
-
-    /**
-     * Creates an intent that launches {@link BlockedAppActivity} when app streaming is blocked.
-     *
-     * Using this method and providing a non-empty {@code streamedDeviceName} will cause the dialog
-     * to use streaming-specific error messages.
-     */
-    public static Intent createStreamingBlockedIntent(int userId, ActivityInfo activityInfo,
-            CharSequence streamedDeviceName) {
-        return new Intent()
-                .setClassName("android", BlockedAppActivity.class.getName())
-                .putExtra(Intent.EXTRA_USER_ID, userId)
-                .putExtra(EXTRA_BLOCKED_ACTIVITY_INFO, activityInfo)
-                .putExtra(EXTRA_STREAMED_DEVICE, streamedDeviceName);
-    }
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index edc8c5b..2bec733 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -18,25 +18,25 @@
 //#define LOG_NDEBUG 0
 
 #define LOG_TAG "AudioSystem-JNI"
-#include <utils/Log.h>
-
-#include <sstream>
-#include <vector>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
 #include <android/media/AudioVibratorInfo.h>
 #include <android/media/INativeSpatializerCallback.h>
 #include <android/media/ISpatializer.h>
+#include <android_os_Parcel.h>
 #include <audiomanager/AudioManager.h>
+#include <jni.h>
 #include <media/AudioContainers.h>
 #include <media/AudioPolicy.h>
 #include <media/AudioSystem.h>
 #include <media/MicrophoneInfo.h>
+#include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
+#include <utils/Log.h>
+
+#include <sstream>
+#include <vector>
+
 #include "android_media_AudioAttributes.h"
 #include "android_media_AudioDescriptor.h"
 #include "android_media_AudioDeviceAttributes.h"
@@ -46,6 +46,7 @@
 #include "android_media_AudioProfile.h"
 #include "android_media_MicrophoneInfo.h"
 #include "android_util_Binder.h"
+#include "core_jni_helpers.h"
 
 // ----------------------------------------------------------------------------
 
@@ -584,18 +585,26 @@
     env->DeleteLocalRef(clazz);
 }
 
-static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
-                                                   jint codec)
-{
-    const char *c_address = env->GetStringUTFChars(device_address, NULL);
-    const char *c_name = env->GetStringUTFChars(device_name, NULL);
-    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
-                                          static_cast <audio_policy_dev_state_t>(state),
-                                          c_address, c_name,
-                                          static_cast <audio_format_t>(codec)));
-    env->ReleaseStringUTFChars(device_address, c_address);
-    env->ReleaseStringUTFChars(device_name, c_name);
+static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
+                                                               jint state, jobject jParcel,
+                                                               jint codec) {
+    int status;
+    if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
+        android::media::audio::common::AudioPort port{};
+        if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) {
+            status = check_AudioSystem_Command(
+                    AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(
+                                                                  state),
+                                                          port,
+                                                          static_cast<audio_format_t>(codec)));
+        } else {
+            ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str());
+            status = kAudioStatusError;
+        }
+    } else {
+        ALOGE("Failed to retrieve the native parcel from Java parcel");
+        status = kAudioStatusError;
+    }
     return (jint) status;
 }
 
@@ -2912,7 +2921,7 @@
          {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
          {"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
          {"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
-         {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I",
+         {"setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
           (void *)android_media_AudioSystem_setDeviceConnectionState},
          {"getDeviceConnectionState", "(ILjava/lang/String;)I",
           (void *)android_media_AudioSystem_getDeviceConnectionState},
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 61b91dd..13ca133 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -873,7 +873,7 @@
             const char* exceptionToThrow;
             char msg[128];
             // TransactionTooLargeException is a checked exception, only throw from certain methods.
-            // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
+            // TODO(b/28321379): Transaction size is the most common cause for FAILED_TRANSACTION
             //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
             //        for other reasons also, such as if the transaction is malformed or
             //        refers to an FD that has been closed.  We should change the driver
@@ -890,8 +890,9 @@
                 exceptionToThrow = (canThrowRemoteException)
                         ? "android/os/DeadObjectException"
                         : "java/lang/RuntimeException";
-                snprintf(msg, sizeof(msg)-1,
-                        "Transaction failed on small parcel; remote process probably died");
+                snprintf(msg, sizeof(msg) - 1,
+                         "Transaction failed on small parcel; remote process probably died, but "
+                         "this could also be caused by running out of binder buffer space");
             }
             jniThrowException(env, exceptionToThrow, msg);
         } break;
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7c67cbc..a6fbf094 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -235,9 +235,7 @@
 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
 {
     ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
-    DIR *d;
     char proc_path[255];
-    struct dirent *de;
 
     if (!verifyGroup(env, grp)) {
         return;
@@ -277,84 +275,8 @@
         }
     }
 
-    sprintf(proc_path, "/proc/%d/task", pid);
-    if (!(d = opendir(proc_path))) {
-        // If the process exited on us, don't generate an exception
-        if (errno != ENOENT)
-            signalExceptionForGroupError(env, errno, pid);
-        return;
-    }
-
-    while ((de = readdir(d))) {
-        int t_pid;
-        int t_pri;
-        std::string taskprofile;
-
-        if (de->d_name[0] == '.')
-            continue;
-        t_pid = atoi(de->d_name);
-
-        if (!t_pid) {
-            ALOGE("Error getting pid for '%s'\n", de->d_name);
-            continue;
-        }
-
-        t_pri = getpriority(PRIO_PROCESS, t_pid);
-
-        if (t_pri <= ANDROID_PRIORITY_AUDIO) {
-            int scheduler = sched_getscheduler(t_pid) & ~SCHED_RESET_ON_FORK;
-            if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
-                // This task wants to stay in its current audio group so it can keep its budget
-                // don't update its cpuset or cgroup
-                continue;
-            }
-        }
-
-        errno = 0;
-        // grp == SP_BACKGROUND. Set background cpuset policy profile for all threads.
-        if (grp == SP_BACKGROUND) {
-            if (!SetTaskProfiles(t_pid, {"CPUSET_SP_BACKGROUND"}, true)) {
-                signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
-                break;
-            }
-            continue;
-        }
-
-        // grp != SP_BACKGROUND. Only change the cpuset cgroup for low priority thread, so it could
-        // preserve it sched policy profile setting.
-        if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
-            switch (grp) {
-                case SP_SYSTEM:
-                    taskprofile = "ServiceCapacityLow";
-                    break;
-                case SP_RESTRICTED:
-                    taskprofile = "ServiceCapacityRestricted";
-                    break;
-                case SP_FOREGROUND:
-                case SP_AUDIO_APP:
-                case SP_AUDIO_SYS:
-                    taskprofile = "ProcessCapacityHigh";
-                    break;
-                case SP_TOP_APP:
-                    taskprofile = "ProcessCapacityMax";
-                    break;
-                default:
-                    taskprofile = "ProcessCapacityNormal";
-                    break;
-            }
-            if (!SetTaskProfiles(t_pid, {taskprofile}, true)) {
-                signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
-                break;
-            }
-        // Change the cpuset policy profile for non-low priority thread according to the grp
-        } else {
-            if (!SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true)) {
-                signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
-                break;
-            }
-        }
-    }
-    closedir(d);
+    if (!SetProcessProfilesCached(0, pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}))
+        signalExceptionForGroupError(env, errno ? errno : EPERM, pid);
 }
 
 void android_os_Process_setProcessFrozen(
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c9d7bfd..74bf152 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -398,6 +398,7 @@
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
+    <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
@@ -977,6 +978,61 @@
         android:permissionFlags="softRestricted|immutablyRestricted"
         android:protectionLevel="dangerous" />
 
+    <!-- Required to be able to read audio files from shared storage.
+     <p>Protection level: dangerous -->
+    <permission-group android:name="android.permission-group.READ_MEDIA_AURAL"
+                      android:icon="@drawable/perm_group_read_media_aural"
+                      android:label="@string/permgrouplab_readMediaAural"
+                      android:description="@string/permgroupdesc_readMediaAural"
+                      android:priority="950" />
+
+    <!-- Allows an application to read audio files from external storage.
+      <p>This permission is enforced starting in API level
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+      For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+      must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+     <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_AUDIO"
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android:label="@string/permlab_readMediaAudio"
+                android:description="@string/permdesc_readMediaAudio"
+                android:protectionLevel="dangerous" />
+
+    <!-- Required to be able to read image and video files from shared storage.
+     <p>Protection level: dangerous -->
+    <permission-group android:name="android.permission-group.READ_MEDIA_VISUAL"
+                      android:icon="@drawable/perm_group_read_media_visual"
+                      android:label="@string/permgrouplab_readMediaVisual"
+                      android:description="@string/permgroupdesc_readMediaVisual"
+                      android:priority="1000" />
+
+    <!-- Allows an application to read audio files from external storage.
+    <p>This permission is enforced starting in API level
+    {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+    For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+    targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+    must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+   <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_VIDEO"
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android:label="@string/permlab_readMediaVideo"
+                android:description="@string/permdesc_readMediaVideo"
+                android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to read image files from external storage.
+      <p>This permission is enforced starting in API level
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+      For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+      must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+     <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_IMAGE"
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android:label="@string/permlab_readMediaImage"
+                android:description="@string/permdesc_readMediaImage"
+                android:protectionLevel="dangerous" />
+
     <!-- Allows an application to write to external storage.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
@@ -6559,6 +6615,13 @@
                   android:exported="false">
         </activity>
 
+        <activity android:name="android.service.games.GameSessionTrampolineActivity"
+                  android:excludeFromRecents="true"
+                  android:exported="true"
+                  android:permission="android.permission.MANAGE_GAME_ACTIVITY"
+                  android:theme="@style/Theme.Translucent.NoTitleBar">
+        </activity>
+
         <receiver android:name="com.android.server.BootReceiver"
                 android:exported="true"
                 android:systemUserOnly="true">
diff --git a/core/res/res/drawable/perm_group_read_media_aural.xml b/core/res/res/drawable/perm_group_read_media_aural.xml
new file mode 100644
index 0000000..6fc9c69
--- /dev/null
+++ b/core/res/res/drawable/perm_group_read_media_aural.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M10,21q-1.65,0 -2.825,-1.175Q6,18.65 6,17q0,-1.65 1.175,-2.825Q8.35,13 10,13q0.575,0 1.063,0.137 0.487,0.138 0.937,0.413V3h6v4h-4v10q0,1.65 -1.175,2.825Q11.65,21 10,21z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_read_media_visual.xml b/core/res/res/drawable/perm_group_read_media_visual.xml
new file mode 100644
index 0000000..a5db271
--- /dev/null
+++ b/core/res/res/drawable/perm_group_read_media_visual.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M9,14h10l-3.45,-4.5 -2.3,3 -1.55,-2zM8,18q-0.825,0 -1.412,-0.587Q6,16.825 6,16L6,4q0,-0.825 0.588,-1.413Q7.175,2 8,2h12q0.825,0 1.413,0.587Q22,3.175 22,4v12q0,0.825 -0.587,1.413Q20.825,18 20,18zM8,16h12L20,4L8,4v12zM4,22q-0.825,0 -1.413,-0.587Q2,20.825 2,20L2,6h2v14h14v2zM8,4v12L8,4z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index afe0f1b..d774fd4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6953,10 +6953,10 @@
     </declare-styleable>
 
     <declare-styleable name="TranslateAnimation">
-        <attr name="fromXDelta" format="float|fraction" />
-        <attr name="toXDelta" format="float|fraction" />
-        <attr name="fromYDelta" format="float|fraction" />
-        <attr name="toYDelta" format="float|fraction" />
+        <attr name="fromXDelta" format="float|fraction|dimension" />
+        <attr name="toXDelta" format="float|fraction|dimension" />
+        <attr name="fromYDelta" format="float|fraction|dimension" />
+        <attr name="toYDelta" format="float|fraction|dimension" />
     </declare-styleable>
 
     <declare-styleable name="AlphaAnimation">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0dbd417..47b4d38 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -876,9 +876,19 @@
     <string name="permgroupdesc_sms">send and view SMS messages</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_storage">Files and media</string>
+    <string name="permgrouplab_storage">Files &amp; documents</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_storage">access photos, media, and files on your device</string>
+    <string name="permgroupdesc_storage">access files and documents on your device</string>
+
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+    <string name="permgrouplab_readMediaAural">Music &amp; other audio</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+    <string name="permgroupdesc_readMediaAural">access audio files on your device</string>
+
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+    <string name="permgrouplab_readMediaVisual">Photos &amp; videos</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+    <string name="permgroupdesc_readMediaVisual">access images and video files on your device</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_microphone">Microphone</string>
@@ -1893,6 +1903,21 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
     <string name="permdesc_sdcardRead">Allows the app to read the contents of your shared storage.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permlab_readMediaAudio">read audio files from shared storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permdesc_readMediaAudio">Allows the app to read audio files from your shared storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permlab_readMediaVideo">read video files from shared storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permdesc_readMediaVideo">Allows the app to read video files from your shared storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permlab_readMediaImage">read image files from shared storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permdesc_readMediaImage">Allows the app to read image files from your shared storage.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
     <string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
@@ -5439,15 +5464,6 @@
         <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is not available right now.
     </string>
 
-    <!-- Title of the dialog shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string>
-    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string>
-    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_message" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your tablet instead.</string>
-    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_message" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your phone instead.</string>
-
     <!-- Message displayed in dialog when app is too old to run on this verison of android. [CHAR LIMIT=NONE] -->
     <string name="deprecated_target_sdk_message">This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer.</string>
     <!-- Title for button to see application detail in app store which it came from - it may allow user to update to newer version. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 764b273..33efbce 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3285,9 +3285,6 @@
   <java-symbol type="string" name="app_blocked_title" />
   <java-symbol type="string" name="app_blocked_message" />
 
-  <java-symbol type="string" name="app_streaming_blocked_title" />
-  <java-symbol type="string" name="app_streaming_blocked_message" />
-
   <!-- Used internally for assistant to launch activity transitions -->
   <java-symbol type="id" name="cross_task_transition" />
 
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 6df9002..ddc27aa 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -42,7 +42,7 @@
     // and assertAccessibilityEventCleared
 
     /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 32;
+    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 33;
 
     // The number of fields tested in the corresponding CTS AccessibilityRecordTest:
     // assertAccessibilityRecordCleared, fullyPopulateAccessibilityRecord,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 92fca36..88920c8 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -231,6 +231,18 @@
                       targetSdk="29">
         <new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
     </split-permission>
+    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
+                      targetSdk="33">
+        <new-permission name="android.permission.READ_MEDIA_AUDIO" />
+    </split-permission>
+    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
+                      targetSdk="33">
+        <new-permission name="android.permission.READ_MEDIA_VIDEO" />
+    </split-permission>
+    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
+                      targetSdk="33">
+        <new-permission name="android.permission.READ_MEDIA_IMAGE" />
+    </split-permission>
     <split-permission name="android.permission.BLUETOOTH"
                       targetSdk="31">
         <new-permission name="android.permission.BLUETOOTH_SCAN" />
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 3732285..1629b6a 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -368,7 +368,7 @@
      * Further, unlike other Sources, this one is not reusable.
      */
     private static class InputStreamSource extends Source {
-        InputStreamSource(Resources res, InputStream is, int inputDensity) {
+        InputStreamSource(Resources res, @NonNull InputStream is, int inputDensity) {
             if (is == null) {
                 throw new IllegalArgumentException("The InputStream cannot be null");
             }
@@ -1020,7 +1020,7 @@
      */
     @AnyThread
     @NonNull
-    public static Source createSource(Resources res, InputStream is) {
+    public static Source createSource(Resources res, @NonNull InputStream is) {
         return new InputStreamSource(res, is, Bitmap.getDefaultDensity());
     }
 
@@ -1034,7 +1034,7 @@
     @AnyThread
     @TestApi
     @NonNull
-    public static Source createSource(Resources res, InputStream is, int density) {
+    public static Source createSource(Resources res, @NonNull InputStream is, int density) {
         return new InputStreamSource(res, is, density);
     }
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 28b3b04..4972e92 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -288,8 +288,7 @@
      *
      * @return A copy of the drawable's bounds
      */
-    @NonNull
-    public final Rect copyBounds() {
+    public final @NonNull Rect copyBounds() {
         return new Rect(mBounds);
     }
 
@@ -308,8 +307,7 @@
      * @see #copyBounds()
      * @see #copyBounds(android.graphics.Rect)
      */
-    @NonNull
-    public final Rect getBounds() {
+    public final @NonNull Rect getBounds() {
         if (mBounds == ZERO_BOUNDS_RECT) {
             mBounds = new Rect();
         }
@@ -327,8 +325,7 @@
      *
      * @return The dirty bounds of this drawable
      */
-    @NonNull
-    public Rect getDirtyBounds() {
+    public @NonNull Rect getDirtyBounds() {
         return getBounds();
     }
 
@@ -457,8 +454,7 @@
      *
      * @see #setCallback(android.graphics.drawable.Drawable.Callback)
      */
-    @Nullable
-    public Callback getCallback() {
+    public @Nullable Callback getCallback() {
         return mCallback != null ? mCallback.get() : null;
     }
 
@@ -569,8 +565,7 @@
      * The default return value is 255 if the class does not override this method to return a value
      * specific to its use of alpha.
      */
-    @IntRange(from=0,to=255)
-    public int getAlpha() {
+    public @IntRange(from=0,to=255) int getAlpha() {
         return 0xFF;
     }
 
@@ -999,7 +994,8 @@
      *
      * @see android.graphics.PixelFormat
      */
-    @Deprecated public abstract @PixelFormat.Opacity int getOpacity();
+    @Deprecated
+    public abstract @PixelFormat.Opacity int getOpacity();
 
     /**
      * Return the appropriate opacity value for two source opacities.  If
@@ -1059,7 +1055,7 @@
      * if it looks the same and there is no need to redraw it since its
      * last state.
      */
-    protected boolean onStateChange(int[] state) {
+    protected boolean onStateChange(@NonNull int[] state) {
         return false;
     }
 
@@ -1078,7 +1074,7 @@
      * Override this in your subclass to change appearance if you vary based on
      * the bounds.
      */
-    protected void onBoundsChange(Rect bounds) {
+    protected void onBoundsChange(@NonNull Rect bounds) {
         // Stub method.
     }
 
@@ -1209,7 +1205,8 @@
     /**
      * Create a drawable from an inputstream
      */
-    public static Drawable createFromStream(InputStream is, String srcName) {
+    public static @Nullable Drawable createFromStream(@Nullable InputStream is,
+            @Nullable String srcName) {
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
         try {
             return createFromResourceStream(null, null, is, srcName);
@@ -1222,8 +1219,8 @@
      * Create a drawable from an inputstream, using the given resources and
      * value to determine density information.
      */
-    public static Drawable createFromResourceStream(Resources res, TypedValue value,
-            InputStream is, String srcName) {
+    public static @Nullable Drawable createFromResourceStream(@Nullable Resources res,
+            @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName) {
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
         try {
             return createFromResourceStream(res, value, is, srcName, null);
@@ -1238,8 +1235,7 @@
      *
      * @deprecated Prefer the version without an Options object.
      */
-    @Nullable
-    public static Drawable createFromResourceStream(@Nullable Resources res,
+    public static @Nullable Drawable createFromResourceStream(@Nullable Resources res,
             @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName,
             @Nullable BitmapFactory.Options opts) {
         if (is == null) {
@@ -1281,7 +1277,8 @@
         return null;
     }
 
-    private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+    private static Drawable getBitmapDrawable(Resources res, @Nullable TypedValue value,
+            @NonNull InputStream is) {
         try {
             ImageDecoder.Source source = null;
             if (value != null) {
@@ -1369,9 +1366,9 @@
      * a tag in an XML document, tries to create a Drawable from that tag.
      * Returns null if the tag is not a valid drawable.
      */
-    @NonNull
-    public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
-            @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
+    public static @NonNull Drawable createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs)
+            throws XmlPullParserException, IOException {
         return createFromXmlInner(r, parser, attrs, null);
     }
 
@@ -1381,9 +1378,8 @@
      * document, tries to create a Drawable from that tag. Returns {@code null}
      * if the tag is not a valid drawable.
      */
-    @NonNull
-    public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
-            @NonNull AttributeSet attrs, @Nullable Theme theme)
+    public static @NonNull Drawable createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         return createFromXmlInnerForDensity(r, parser, attrs, 0, theme);
     }
@@ -1392,8 +1388,7 @@
      * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that
      * accepts an override density.
      */
-    @NonNull
-    static Drawable createFromXmlInnerForDensity(@NonNull Resources r,
+    static @NonNull Drawable createFromXmlInnerForDensity(@NonNull Resources r,
             @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density,
             @Nullable Theme theme) throws XmlPullParserException, IOException {
         return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs,
@@ -1403,8 +1398,7 @@
     /**
      * Create a drawable from file path name.
      */
-    @Nullable
-    public static Drawable createFromPath(String pathName) {
+    public static @Nullable Drawable createFromPath(String pathName) {
         if (pathName == null) {
             return null;
         }
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index 66752a2..8debe26 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -61,8 +61,7 @@
      * @param id the identifier of the drawable resource
      * @return a drawable, or {@code null} if the drawable failed to load
      */
-    @Nullable
-    public static Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) {
+    public static @Nullable Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) {
         return loadDrawable(context.getResources(), context.getTheme(), id);
     }
 
@@ -74,9 +73,8 @@
      * @param id the identifier of the drawable resource
      * @return a drawable, or {@code null} if the drawable failed to load
      */
-    @Nullable
-    public static Drawable loadDrawable(
-            @NonNull Resources resources, @Nullable Theme theme, @DrawableRes int id) {
+    public static @Nullable Drawable loadDrawable(@NonNull Resources resources,
+            @Nullable Theme theme, @DrawableRes int id) {
         return resources.getDrawable(id, theme);
     }
 
@@ -111,8 +109,7 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    @NonNull
-    public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
+    public @NonNull Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         return inflateFromXmlForDensity(name, parser, attrs, 0, theme);
@@ -122,8 +119,7 @@
      * Version of {@link #inflateFromXml(String, XmlPullParser, AttributeSet, Theme)} that accepts
      * an override density.
      */
-    @NonNull
-    Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser,
+    @NonNull Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, int density, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         // Inner classes must be referenced as Outer$Inner, but XML tag names
@@ -146,9 +142,8 @@
         return drawable;
     }
 
-    @NonNull
     @SuppressWarnings("deprecation")
-    private Drawable inflateFromTag(@NonNull String name) {
+    private @Nullable Drawable inflateFromTag(@NonNull String name) {
         switch (name) {
             case "selector":
                 return new StateListDrawable();
@@ -195,8 +190,7 @@
         }
     }
 
-    @NonNull
-    private Drawable inflateFromClass(@NonNull String className) {
+    private @NonNull Drawable inflateFromClass(@NonNull String className) {
         try {
             Constructor<? extends Drawable> constructor;
             synchronized (CONSTRUCTOR_MAP) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index ebde757..a63d7f6 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -352,7 +352,7 @@
     }
 
     @Override
-    protected boolean onStateChange(int[] state) {
+    protected boolean onStateChange(@NonNull int[] state) {
         if (mDrawable != null && mDrawable.isStateful()) {
             final boolean changed = mDrawable.setState(state);
             if (changed) {
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index a03931b..b04b826 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -302,7 +302,7 @@
      *                is available. The {@link android.os.Message#obj obj}
      *                property is populated with the Drawable.
      */
-    public void loadDrawableAsync(Context context, Message andThen) {
+    public void loadDrawableAsync(@NonNull Context context, @NonNull Message andThen) {
         if (andThen.getTarget() == null) {
             throw new IllegalArgumentException("callback message must have a target handler");
         }
@@ -320,7 +320,7 @@
      *                 {@link #loadDrawable(Context)} finished
      * @param handler {@link Handler} on which to notify the {@code listener}
      */
-    public void loadDrawableAsync(Context context, final OnDrawableLoadedListener listener,
+    public void loadDrawableAsync(@NonNull Context context, final OnDrawableLoadedListener listener,
             Handler handler) {
         new LoadDrawableTask(context, handler, listener).runAsync();
     }
@@ -335,7 +335,7 @@
      *                to access {@link android.content.res.Resources Resources}, for example.
      * @return A fresh instance of a drawable for this image, yours to keep.
      */
-    public Drawable loadDrawable(Context context) {
+    public @Nullable Drawable loadDrawable(Context context) {
         final Drawable result = loadDrawableInner(context);
         if (result != null && hasTint()) {
             result.mutate();
@@ -415,7 +415,7 @@
         return null;
     }
 
-    private InputStream getUriInputStream(Context context) {
+    private @Nullable InputStream getUriInputStream(Context context) {
         final Uri uri = getUri();
         final String scheme = uri.getScheme();
         if (ContentResolver.SCHEME_CONTENT.equals(scheme)
@@ -496,7 +496,7 @@
      * @param stream The stream on which to serialize the Icon.
      * @hide
      */
-    public void writeToStream(OutputStream stream) throws IOException {
+    public void writeToStream(@NonNull OutputStream stream) throws IOException {
         DataOutputStream dataStream = new DataOutputStream(stream);
 
         dataStream.writeInt(VERSION_STREAM_SERIALIZER);
@@ -532,7 +532,7 @@
      * @param stream The input stream from which to reconstruct the Icon.
      * @hide
      */
-    public static Icon createFromStream(InputStream stream) throws IOException {
+    public static @Nullable Icon createFromStream(@NonNull InputStream stream) throws IOException {
         DataInputStream inputStream = new DataInputStream(stream);
 
         final int version = inputStream.readInt();
@@ -571,7 +571,7 @@
      * @return whether this icon is the same as the another one
      * @hide
      */
-    public boolean sameAs(Icon otherIcon) {
+    public boolean sameAs(@NonNull Icon otherIcon) {
         if (otherIcon == this) {
             return true;
         }
@@ -602,7 +602,7 @@
      *                given resource ID.
      * @param resId ID of the drawable resource
      */
-    public static Icon createWithResource(Context context, @DrawableRes int resId) {
+    public static @NonNull Icon createWithResource(Context context, @DrawableRes int resId) {
         if (context == null) {
             throw new IllegalArgumentException("Context must not be null.");
         }
@@ -617,7 +617,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static Icon createWithResource(Resources res, @DrawableRes int resId) {
+    public static @NonNull Icon createWithResource(Resources res, @DrawableRes int resId) {
         if (res == null) {
             throw new IllegalArgumentException("Resource must not be null.");
         }
@@ -632,7 +632,7 @@
      * @param resPackage Name of the package containing the resource in question
      * @param resId ID of the drawable resource
      */
-    public static Icon createWithResource(String resPackage, @DrawableRes int resId) {
+    public static @NonNull Icon createWithResource(String resPackage, @DrawableRes int resId) {
         if (resPackage == null) {
             throw new IllegalArgumentException("Resource package name must not be null.");
         }
@@ -646,7 +646,7 @@
      * Create an Icon pointing to a bitmap in memory.
      * @param bits A valid {@link android.graphics.Bitmap} object
      */
-    public static Icon createWithBitmap(Bitmap bits) {
+    public static @NonNull Icon createWithBitmap(Bitmap bits) {
         if (bits == null) {
             throw new IllegalArgumentException("Bitmap must not be null.");
         }
@@ -660,7 +660,7 @@
      * by {@link AdaptiveIconDrawable}.
      * @param bits A valid {@link android.graphics.Bitmap} object
      */
-    public static Icon createWithAdaptiveBitmap(Bitmap bits) {
+    public static @NonNull Icon createWithAdaptiveBitmap(Bitmap bits) {
         if (bits == null) {
             throw new IllegalArgumentException("Bitmap must not be null.");
         }
@@ -677,7 +677,7 @@
      * @param offset Offset into <code>data</code> at which the bitmap data starts
      * @param length Length of the bitmap data
      */
-    public static Icon createWithData(byte[] data, int offset, int length) {
+    public static @NonNull Icon createWithData(byte[] data, int offset, int length) {
         if (data == null) {
             throw new IllegalArgumentException("Data must not be null.");
         }
@@ -693,7 +693,7 @@
      *
      * @param uri A uri referring to local content:// or file:// image data.
      */
-    public static Icon createWithContentUri(String uri) {
+    public static @NonNull Icon createWithContentUri(String uri) {
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
@@ -707,7 +707,7 @@
      *
      * @param uri A uri referring to local content:// or file:// image data.
      */
-    public static Icon createWithContentUri(Uri uri) {
+    public static @NonNull Icon createWithContentUri(Uri uri) {
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
@@ -720,8 +720,7 @@
      *
      * @param uri A uri referring to local content:// or file:// image data.
      */
-    @NonNull
-    public static Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) {
+    public static @NonNull Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) {
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
@@ -750,7 +749,7 @@
      * @param tint a color, as in {@link Drawable#setTint(int)}
      * @return this same object, for use in chained construction
      */
-    public Icon setTint(@ColorInt int tint) {
+    public @NonNull Icon setTint(@ColorInt int tint) {
         return setTintList(ColorStateList.valueOf(tint));
     }
 
@@ -760,7 +759,7 @@
      * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint
      * @return this same object, for use in chained construction
      */
-    public Icon setTintList(ColorStateList tintList) {
+    public @NonNull Icon setTintList(ColorStateList tintList) {
         mTintList = tintList;
         return this;
     }
@@ -809,7 +808,7 @@
      * @param path A path to a file that contains compressed bitmap data of
      *           a type that {@link android.graphics.BitmapFactory} can decode.
      */
-    public static Icon createWithFilePath(String path) {
+    public static @NonNull Icon createWithFilePath(String path) {
         if (path == null) {
             throw new IllegalArgumentException("Path must not be null.");
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 72ead00..32861b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -103,7 +103,7 @@
         };
         context.registerReceiverForAllUsers(closeSystemDialogsBroadcastReceiver,
                 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null /* permission */,
-                mainHandler);
+                mainHandler, Context.RECEIVER_EXPORTED);
 
         pipMediaController.addActionListener(this::onMediaActionsChanged);
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 6524182..9061239 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -93,7 +93,7 @@
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                     .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                            repetitions = 20)
+                            repetitions = 5)
         }
     }
 }
\ No newline at end of file
diff --git a/media/Android.bp b/media/Android.bp
index fcdfd72..5aedcfb 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -108,6 +108,11 @@
             vndk: {
                 enabled: true,
             },
+            min_sdk_version: "29",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.bluetooth",
+            ],
         },
     },
 }
diff --git a/media/java/android/media/AudioDescriptor.java b/media/java/android/media/AudioDescriptor.java
index 11371b1..df648be 100644
--- a/media/java/android/media/AudioDescriptor.java
+++ b/media/java/android/media/AudioDescriptor.java
@@ -18,16 +18,21 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * The AudioDescriptor contains the information to describe the audio playback/capture
  * capabilities. The capabilities are described by a byte array, which is defined by a
  * particular standard. This is used when the format is unrecognized to the platform.
  */
-public class AudioDescriptor {
+public class AudioDescriptor implements Parcelable {
     /**
      * The audio standard is not specified.
      */
@@ -49,7 +54,15 @@
     private final byte[] mDescriptor;
     private final int mEncapsulationType;
 
-    AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
+    /**
+     * @hide
+     * Constructor from standard, encapsulation type and descriptor
+     * @param standard the standard of the audio descriptor
+     * @param encapsulationType the encapsulation type of the audio descriptor
+     * @param descriptor the audio descriptor
+     */
+    @SystemApi
+    public AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
         mStandard = standard;
         mEncapsulationType = encapsulationType;
         mDescriptor = descriptor;
@@ -87,4 +100,66 @@
     public @AudioProfile.EncapsulationType int getEncapsulationType() {
         return mEncapsulationType;
     }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStandard, mEncapsulationType, Arrays.hashCode(mDescriptor));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioDescriptor that = (AudioDescriptor) o;
+        return ((mStandard == that.mStandard)
+                && (mEncapsulationType == that.mEncapsulationType)
+                && (Arrays.equals(mDescriptor, that.mDescriptor)));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("{");
+        sb.append("standard=" + mStandard);
+        sb.append(", encapsulation type=" + mEncapsulationType);
+        if (mDescriptor != null && mDescriptor.length > 0) {
+            sb.append(", descriptor=").append(Arrays.toString(mDescriptor));
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStandard);
+        dest.writeInt(mEncapsulationType);
+        dest.writeByteArray(mDescriptor);
+    }
+
+    private AudioDescriptor(@NonNull Parcel in) {
+        mStandard = in.readInt();
+        mEncapsulationType = in.readInt();
+        mDescriptor = in.createByteArray();
+    }
+
+    public static final @NonNull Parcelable.Creator<AudioDescriptor> CREATOR =
+            new Parcelable.Creator<AudioDescriptor>() {
+                /**
+                 * Rebuilds an AudioDescriptor previously stored with writeToParcel().
+                 * @param p Parcel object to read the AudioDescriptor from
+                 * @return a new AudioDescriptor created from the data in the parcel
+                 */
+                public AudioDescriptor createFromParcel(Parcel p) {
+                    return new AudioDescriptor(p);
+                }
+
+                public AudioDescriptor[] newArray(int size) {
+                    return new AudioDescriptor[size];
+                }
+            };
 }
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java
index 1448c49..af3c295 100644
--- a/media/java/android/media/AudioDeviceAttributes.java
+++ b/media/java/android/media/AudioDeviceAttributes.java
@@ -18,12 +18,16 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -65,16 +69,27 @@
      * The unique address of the device. Some devices don't have addresses, only an empty string.
      */
     private final @NonNull String mAddress;
-
+    /**
+     * The non-unique name of the device. Some devices don't have names, only an empty string.
+     * Should not be used as a unique identifier for a device.
+     */
+    private final @NonNull String mName;
     /**
      * Is input or output device
      */
     private final @Role int mRole;
-
     /**
      * The internal audio device type
      */
     private final int mNativeType;
+    /**
+     * List of AudioProfiles supported by the device
+     */
+    private final @NonNull List<AudioProfile> mAudioProfiles;
+    /**
+     * List of AudioDescriptors supported by the device
+     */
+    private final @NonNull List<AudioDescriptor> mAudioDescriptors;
 
     /**
      * @hide
@@ -88,7 +103,10 @@
         mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
         mType = deviceInfo.getType();
         mAddress = deviceInfo.getAddress();
+        mName = String.valueOf(deviceInfo.getProductName());
         mNativeType = deviceInfo.getInternalType();
+        mAudioProfiles = deviceInfo.getAudioProfiles();
+        mAudioDescriptors = deviceInfo.getAudioDescriptors();
     }
 
     /**
@@ -100,7 +118,24 @@
      */
     @SystemApi
     public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
-                              @NonNull String address) {
+            @NonNull String address) {
+        this(role, type, address, "", new ArrayList<>(), new ArrayList<>());
+    }
+
+    /**
+     * @hide
+     * Constructor with specification of all attributes
+     * @param role indicates input or output role
+     * @param type the device type, as defined in {@link AudioDeviceInfo}
+     * @param address the address of the device, or an empty string for devices without one
+     * @param name the name of the device, or an empty string for devices without one
+     * @param profiles the list of AudioProfiles supported by the device
+     * @param descriptors the list of AudioDescriptors supported by the device
+     */
+    @SystemApi
+    public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
+            @NonNull String address, @NonNull String name, @NonNull List<AudioProfile> profiles,
+            @NonNull List<AudioDescriptor> descriptors) {
         Objects.requireNonNull(address);
         if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
             throw new IllegalArgumentException("Invalid role " + role);
@@ -118,19 +153,37 @@
         mRole = role;
         mType = type;
         mAddress = address;
+        mName = name;
+        mAudioProfiles = profiles;
+        mAudioDescriptors = descriptors;
     }
 
     /**
      * @hide
-     * Constructor from internal device type and address
-     * @param type the internal device type, as defined in {@link AudioSystem}
+     * Constructor called from AudioSystem JNI when creating an AudioDeviceAttributes from a native
+     * AudioDeviceTypeAddr instance.
+     * @param nativeType the internal device type, as defined in {@link AudioSystem}
      * @param address the address of the device, or an empty string for devices without one
      */
     public AudioDeviceAttributes(int nativeType, @NonNull String address) {
+        this(nativeType, address, "");
+    }
+
+    /**
+     * @hide
+     * Constructor called from BtHelper to connect or disconnect a Bluetooth device.
+     * @param nativeType the internal device type, as defined in {@link AudioSystem}
+     * @param address the address of the device, or an empty string for devices without one
+     * @param name the name of the device, or an empty string for devices without one
+     */
+    public AudioDeviceAttributes(int nativeType, @NonNull String address, @NonNull String name) {
         mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
         mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
         mAddress = address;
+        mName = name;
         mNativeType = nativeType;
+        mAudioProfiles = new ArrayList<>();
+        mAudioDescriptors = new ArrayList<>();
     }
 
     /**
@@ -165,6 +218,16 @@
 
     /**
      * @hide
+     * Returns the name of the audio device, or an empty string for devices without one
+     * @return the device name
+     */
+    @SystemApi
+    public @NonNull String getName() {
+        return mName;
+    }
+
+    /**
+     * @hide
      * Returns the internal device type of a device
      * @return the internal device type
      */
@@ -172,9 +235,29 @@
         return mNativeType;
     }
 
+    /**
+     * @hide
+     * Returns the list of AudioProfiles supported by the device
+     * @return the list of AudioProfiles
+     */
+    @SystemApi
+    public @NonNull List<AudioProfile> getAudioProfiles() {
+        return mAudioProfiles;
+    }
+
+    /**
+     * @hide
+     * Returns the list of AudioDescriptors supported by the device
+     * @return the list of AudioDescriptors
+     */
+    @SystemApi
+    public @NonNull List<AudioDescriptor> getAudioDescriptors() {
+        return mAudioDescriptors;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(mRole, mType, mAddress);
+        return Objects.hash(mRole, mType, mAddress, mName, mAudioProfiles, mAudioDescriptors);
     }
 
     @Override
@@ -185,6 +268,25 @@
         AudioDeviceAttributes that = (AudioDeviceAttributes) o;
         return ((mRole == that.mRole)
                 && (mType == that.mType)
+                && mAddress.equals(that.mAddress)
+                && mName.equals(that.mName)
+                && mAudioProfiles.equals(that.mAudioProfiles)
+                && mAudioDescriptors.equals(that.mAudioDescriptors));
+    }
+
+    /**
+     * Returns true if the role, type and address are equal. Called to compare with an
+     * AudioDeviceAttributes that was created from a native AudioDeviceTypeAddr instance.
+     * @param o object to compare with
+     * @return whether role, type and address are equal
+     */
+    public boolean equalTypeAddress(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioDeviceAttributes that = (AudioDeviceAttributes) o;
+        return ((mRole == that.mRole)
+                && (mType == that.mType)
                 && mAddress.equals(that.mAddress));
     }
 
@@ -199,7 +301,10 @@
                 + " role:" + roleToString(mRole)
                 + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
                         : AudioSystem.getInputDeviceName(mNativeType))
-                + " addr:" + mAddress);
+                + " addr:" + mAddress
+                + " name:" + mName
+                + " profiles:" + mAudioProfiles.toString()
+                + " descriptors:" + mAudioDescriptors.toString());
     }
 
     @Override
@@ -212,14 +317,26 @@
         dest.writeInt(mRole);
         dest.writeInt(mType);
         dest.writeString(mAddress);
+        dest.writeString(mName);
         dest.writeInt(mNativeType);
+        dest.writeParcelableArray(
+                mAudioProfiles.toArray(new AudioProfile[mAudioProfiles.size()]), flags);
+        dest.writeParcelableArray(
+                mAudioDescriptors.toArray(new AudioDescriptor[mAudioDescriptors.size()]), flags);
     }
 
     private AudioDeviceAttributes(@NonNull Parcel in) {
         mRole = in.readInt();
         mType = in.readInt();
         mAddress = in.readString();
+        mName = in.readString();
         mNativeType = in.readInt();
+        AudioProfile[] audioProfilesArray =
+                in.readParcelableArray(AudioProfile.class.getClassLoader(), AudioProfile.class);
+        mAudioProfiles = new ArrayList<AudioProfile>(Arrays.asList(audioProfilesArray));
+        AudioDescriptor[] audioDescriptorsArray = in.readParcelableArray(
+                AudioDescriptor.class.getClassLoader(), AudioDescriptor.class);
+        mAudioDescriptors = new ArrayList<AudioDescriptor>(Arrays.asList(audioDescriptorsArray));
     }
 
     public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index dd17dc6..3d08959 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -421,7 +421,7 @@
      */
     public CharSequence getProductName() {
         String portName = mPort.name();
-        return portName.length() != 0 ? portName : android.os.Build.MODEL;
+        return (portName != null && portName.length() != 0) ? portName : android.os.Build.MODEL;
     }
 
     /**
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b8333fb..cdc3163 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5874,7 +5874,7 @@
         return false;
     }
 
-     /**
+    /**
      * Indicate wired accessory connection state change.
      * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
      * @param state  new connection state: 1 connected, 0 disconnected
@@ -5883,10 +5883,29 @@
      */
     @UnsupportedAppUsage
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
+    public void setWiredDeviceConnectionState(int device, int state, String address,
+            String name) {
+        final IAudioService service = getService();
+        int role = isOutputDevice(device)
+                ? AudioDeviceAttributes.ROLE_OUTPUT : AudioDeviceAttributes.ROLE_INPUT;
+        AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+                role, AudioDeviceInfo.convertInternalDeviceToDeviceType(device), address,
+                name, new ArrayList<>()/*mAudioProfiles*/, new ArrayList<>()/*mAudioDescriptors*/);
+        setWiredDeviceConnectionState(attributes, state);
+    }
+
+    /**
+     * Indicate wired accessory connection state change and attributes.
+     * @param state      new connection state: 1 connected, 0 disconnected
+     * @param attributes attributes of the connected device
+     * {@hide}
+     */
+    @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
         final IAudioService service = getService();
         try {
-            service.setWiredDeviceConnectionState(type, state, address, name,
+            service.setWiredDeviceConnectionState(attributes, state,
                     mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/media/java/android/media/AudioProfile.java b/media/java/android/media/AudioProfile.java
index ae8d0a5..5c5f837 100644
--- a/media/java/android/media/AudioProfile.java
+++ b/media/java/android/media/AudioProfile.java
@@ -18,10 +18,14 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -33,7 +37,7 @@
  * be reported in different audio profiles. The application can choose any of the encapsulation
  * types.
  */
-public class AudioProfile {
+public class AudioProfile implements Parcelable {
     /**
      * No encapsulation type is specified.
      */
@@ -57,9 +61,19 @@
     private final int[] mChannelIndexMasks;
     private final int mEncapsulationType;
 
-    AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
-                 @NonNull int[] channelIndexMasks,
-                 int encapsulationType) {
+    /**
+     * @hide
+     * Constructor from format, sampling rates, channel masks, channel index masks and
+     * encapsulation type.
+     * @param format the audio format
+     * @param samplingRates the supported sampling rates
+     * @param channelMasks the supported channel masks
+     * @param channelIndexMasks the supported channel index masks
+     * @param encapsulationType the encapsulation type of the encoding format
+     */
+    @SystemApi
+    public AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
+                 @NonNull int[] channelIndexMasks, int encapsulationType) {
         mFormat = format;
         mSamplingRates = samplingRates;
         mChannelMasks = channelMasks;
@@ -114,6 +128,26 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hash(mFormat, Arrays.hashCode(mSamplingRates),
+                Arrays.hashCode(mChannelMasks), Arrays.hashCode(mChannelIndexMasks),
+                mEncapsulationType);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioProfile that = (AudioProfile) o;
+        return ((mFormat == that.mFormat)
+                && (hasIdenticalElements(mSamplingRates, that.mSamplingRates))
+                && (hasIdenticalElements(mChannelMasks, that.mChannelMasks))
+                && (hasIdenticalElements(mChannelIndexMasks, that.mChannelIndexMasks))
+                && (mEncapsulationType == that.mEncapsulationType));
+    }
+
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("{");
         sb.append(AudioFormat.toLogFriendlyEncoding(mFormat));
@@ -126,6 +160,7 @@
         if (mChannelIndexMasks != null && mChannelIndexMasks.length > 0) {
             sb.append(", channel index masks=").append(Arrays.toString(mChannelIndexMasks));
         }
+        sb.append(", encapsulation type=" + mEncapsulationType);
         sb.append("}");
         return sb.toString();
     }
@@ -137,4 +172,50 @@
         return Arrays.stream(ints).mapToObj(anInt -> String.format("0x%02X", anInt))
                 .collect(Collectors.joining(", "));
     }
+
+    private static boolean hasIdenticalElements(int[] array1, int[] array2) {
+        int[] sortedArray1 = Arrays.copyOf(array1, array1.length);
+        Arrays.sort(sortedArray1);
+        int[] sortedArray2 = Arrays.copyOf(array2, array2.length);
+        Arrays.sort(sortedArray2);
+        return Arrays.equals(sortedArray1, sortedArray2);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mFormat);
+        dest.writeIntArray(mSamplingRates);
+        dest.writeIntArray(mChannelMasks);
+        dest.writeIntArray(mChannelIndexMasks);
+        dest.writeInt(mEncapsulationType);
+    }
+
+    private AudioProfile(@NonNull Parcel in) {
+        mFormat = in.readInt();
+        mSamplingRates = in.createIntArray();
+        mChannelMasks = in.createIntArray();
+        mChannelIndexMasks = in.createIntArray();
+        mEncapsulationType = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<AudioProfile> CREATOR =
+            new Parcelable.Creator<AudioProfile>() {
+                /**
+                 * Rebuilds an AudioProfile previously stored with writeToParcel().
+                 * @param p Parcel object to read the AudioProfile from
+                 * @return a new AudioProfile created from the data in the parcel
+                 */
+                public AudioProfile createFromParcel(Parcel p) {
+                    return new AudioProfile(p);
+                }
+
+                public AudioProfile[] newArray(int size) {
+                    return new AudioProfile[size];
+                }
+            };
 }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 1b46a50..536b4ad 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -26,10 +26,12 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.audio.common.AidlConversion;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
 import android.os.Build;
 import android.os.IBinder;
+import android.os.Parcel;
 import android.os.Vibrator;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -1555,9 +1557,24 @@
      *     {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED}
      */
     @UnsupportedAppUsage
-    public static native int setDeviceConnectionState(int device, int state,
-                                                      String device_address, String device_name,
-                                                      int codecFormat);
+    public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+            int codecFormat) {
+        android.media.audio.common.AudioPort port =
+                AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
+        Parcel parcel = Parcel.obtain();
+        port.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        try {
+            return setDeviceConnectionState(state, parcel, codecFormat);
+        } finally {
+            parcel.recycle();
+        }
+    }
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat);
     /** @hide */
     @UnsupportedAppUsage
     public static native int getDeviceConnectionState(int device, String device_address);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4451c64..fec14de 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -215,8 +215,7 @@
     IRingtonePlayer getRingtonePlayer();
     int getUiSoundsStreamType();
 
-    void setWiredDeviceConnectionState(int type, int state, String address, String name,
-            String caller);
+    void setWiredDeviceConnectionState(in AudioDeviceAttributes aa, int state, String caller);
 
     @UnsupportedAppUsage
     AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
index 1053fb7..f17189de 100644
--- a/media/java/android/media/audio/common/AidlConversion.java
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -17,12 +17,17 @@
 package android.media.audio.common;
 
 import android.annotation.NonNull;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioFormat;
+import android.media.AudioSystem;
 import android.media.MediaFormat;
 import android.os.Parcel;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.stream.Collectors;
+
 /**
  * This class provides utility functions for converting between
  * the AIDL types defined in 'android.media.audio.common' and:
@@ -525,6 +530,351 @@
         }
     }
 
+    /**
+     * Convert from SDK AudioDeviceAttributes to AIDL AudioPort.
+     */
+    public static AudioPort api2aidl_AudioDeviceAttributes_AudioPort(
+            @NonNull AudioDeviceAttributes attributes) {
+        AudioPort port = new AudioPort();
+        port.name = attributes.getName();
+        // TO DO: b/211611504 Convert attributes.getAudioProfiles() to AIDL as well.
+        port.profiles = new AudioProfile[]{};
+        port.extraAudioDescriptors = attributes.getAudioDescriptors().stream()
+                .map(descriptor -> api2aidl_AudioDescriptor_ExtraAudioDescriptor(descriptor))
+                .collect(Collectors.toList()).toArray(ExtraAudioDescriptor[]::new);
+        port.flags = new AudioIoFlags();
+        port.gains = new AudioGain[]{};
+        AudioPortDeviceExt deviceExt = new AudioPortDeviceExt();
+        deviceExt.device = new AudioDevice();
+        deviceExt.encodedFormats = new AudioFormatDescription[]{};
+        deviceExt.device.type =
+                api2aidl_NativeType_AudioDeviceDescription(attributes.getInternalType());
+        deviceExt.device.address = AudioDeviceAddress.id(attributes.getAddress());
+        port.ext = AudioPortExt.device(deviceExt);
+        return port;
+    }
+
+    /**
+     * Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
+     */
+    public static ExtraAudioDescriptor api2aidl_AudioDescriptor_ExtraAudioDescriptor(
+            @NonNull AudioDescriptor descriptor) {
+        ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+        extraDescriptor.standard =
+                api2aidl_AudioDescriptorStandard_AudioStandard(descriptor.getStandard());
+        extraDescriptor.audioDescriptor = descriptor.getDescriptor();
+        extraDescriptor.encapsulationType =
+                api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
+                        descriptor.getEncapsulationType());
+        return extraDescriptor;
+    }
+
+    /**
+     * Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
+     */
+    public static @NonNull AudioDescriptor aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+            @NonNull ExtraAudioDescriptor extraDescriptor) {
+        AudioDescriptor descriptor = new AudioDescriptor(
+                aidl2api_AudioStandard_AudioDescriptorStandard(extraDescriptor.standard),
+                aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
+                        extraDescriptor.encapsulationType),
+                extraDescriptor.audioDescriptor);
+        return descriptor;
+    }
+
+    /**
+     * Convert from SDK AudioDescriptor#mStandard to AIDL AudioStandard
+     */
+    @AudioStandard
+    public static int api2aidl_AudioDescriptorStandard_AudioStandard(
+            @AudioDescriptor.AudioDescriptorStandard int standard) {
+        switch (standard) {
+            case AudioDescriptor.STANDARD_EDID:
+                return AudioStandard.EDID;
+            case AudioDescriptor.STANDARD_NONE:
+            default:
+                return AudioStandard.NONE;
+        }
+    }
+
+    /**
+     * Convert from AIDL AudioStandard to SDK AudioDescriptor#mStandard
+     */
+    @AudioDescriptor.AudioDescriptorStandard
+    public static int aidl2api_AudioStandard_AudioDescriptorStandard(@AudioStandard int standard) {
+        switch (standard) {
+            case AudioStandard.EDID:
+                return AudioDescriptor.STANDARD_EDID;
+            case AudioStandard.NONE:
+            default:
+                return AudioDescriptor.STANDARD_NONE;
+        }
+    }
+
+    /**
+     * Convert from SDK AudioProfile.EncapsulationType to AIDL AudioEncapsulationType
+     */
+    @AudioEncapsulationType
+    public static int api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
+            @android.media.AudioProfile.EncapsulationType int type) {
+        switch (type) {
+            case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937:
+                return AudioEncapsulationType.IEC61937;
+            case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE:
+            default:
+                return AudioEncapsulationType.NONE;
+        }
+    }
+
+    /**
+     * Convert from AIDL AudioEncapsulationType to SDK AudioProfile.EncapsulationType
+     */
+    @android.media.AudioProfile.EncapsulationType
+    public static int aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
+            @AudioEncapsulationType int type) {
+        switch (type) {
+            case AudioEncapsulationType.IEC61937:
+                return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937;
+            case AudioEncapsulationType.NONE:
+            default:
+                return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE;
+        }
+    }
+
+    /**
+     * Convert from SDK native type to AIDL AudioDeviceDescription
+     */
+    public static AudioDeviceDescription api2aidl_NativeType_AudioDeviceDescription(
+            int nativeType) {
+        AudioDeviceDescription aidl = new AudioDeviceDescription();
+        aidl.connection = "";
+        switch (nativeType) {
+            case AudioSystem.DEVICE_OUT_EARPIECE:
+                aidl.type = AudioDeviceType.OUT_SPEAKER_EARPIECE;
+                break;
+            case AudioSystem.DEVICE_OUT_SPEAKER:
+                aidl.type = AudioDeviceType.OUT_SPEAKER;
+                break;
+            case AudioSystem.DEVICE_OUT_WIRED_HEADPHONE:
+                aidl.type = AudioDeviceType.OUT_HEADPHONE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+                aidl.type = AudioDeviceType.OUT_CARKIT;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+                aidl.type = AudioDeviceType.OUT_HEADPHONE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+                aidl.type = AudioDeviceType.OUT_SPEAKER;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_OUT_TELEPHONY_TX:
+                aidl.type = AudioDeviceType.OUT_TELEPHONY_TX;
+                break;
+            case AudioSystem.DEVICE_OUT_AUX_LINE:
+                aidl.type = AudioDeviceType.OUT_LINE_AUX;
+                break;
+            case AudioSystem.DEVICE_OUT_SPEAKER_SAFE:
+                aidl.type = AudioDeviceType.OUT_SPEAKER_SAFE;
+                break;
+            case AudioSystem.DEVICE_OUT_HEARING_AID:
+                aidl.type = AudioDeviceType.OUT_HEARING_AID;
+                aidl.connection = AudioDeviceDescription.CONNECTION_WIRELESS;
+                break;
+            case AudioSystem.DEVICE_OUT_ECHO_CANCELLER:
+                aidl.type = AudioDeviceType.OUT_ECHO_CANCELLER;
+                break;
+            case AudioSystem.DEVICE_OUT_BLE_SPEAKER:
+                aidl.type = AudioDeviceType.OUT_SPEAKER;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_IN_BUILTIN_MIC:
+                aidl.type = AudioDeviceType.IN_MICROPHONE;
+                break;
+            case AudioSystem.DEVICE_IN_BACK_MIC:
+                aidl.type = AudioDeviceType.IN_MICROPHONE_BACK;
+                break;
+            case AudioSystem.DEVICE_IN_TELEPHONY_RX:
+                aidl.type = AudioDeviceType.IN_TELEPHONY_RX;
+                break;
+            case AudioSystem.DEVICE_IN_TV_TUNER:
+                aidl.type = AudioDeviceType.IN_TV_TUNER;
+                break;
+            case AudioSystem.DEVICE_IN_LOOPBACK:
+                aidl.type = AudioDeviceType.IN_LOOPBACK;
+                break;
+            case AudioSystem.DEVICE_IN_BLUETOOTH_BLE:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_IN_ECHO_REFERENCE:
+                aidl.type = AudioDeviceType.IN_ECHO_REFERENCE;
+                break;
+            case AudioSystem.DEVICE_IN_WIRED_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_WIRED_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_IN_HDMI:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
+                break;
+            case AudioSystem.DEVICE_OUT_HDMI:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
+                break;
+            case AudioSystem.DEVICE_IN_REMOTE_SUBMIX:
+                aidl.type = AudioDeviceType.IN_SUBMIX;
+                break;
+            case AudioSystem.DEVICE_OUT_REMOTE_SUBMIX:
+                aidl.type = AudioDeviceType.OUT_SUBMIX;
+                break;
+            case AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.IN_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.OUT_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.IN_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.OUT_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_USB_ACCESSORY:
+                aidl.type = AudioDeviceType.IN_ACCESSORY;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_USB_ACCESSORY:
+                aidl.type = AudioDeviceType.OUT_ACCESSORY;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_USB_DEVICE:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_USB_DEVICE:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_FM_TUNER:
+                aidl.type = AudioDeviceType.IN_FM_TUNER;
+                break;
+            case AudioSystem.DEVICE_OUT_FM:
+                aidl.type = AudioDeviceType.OUT_FM;
+                break;
+            case AudioSystem.DEVICE_IN_LINE:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_LINE:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_IN_SPDIF:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
+                break;
+            case AudioSystem.DEVICE_OUT_SPDIF:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
+                break;
+            case AudioSystem.DEVICE_IN_BLUETOOTH_A2DP:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_IN_IP:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
+                break;
+            case AudioSystem.DEVICE_OUT_IP:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
+                break;
+            case AudioSystem.DEVICE_IN_BUS:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
+                break;
+            case AudioSystem.DEVICE_OUT_BUS:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
+                break;
+            case AudioSystem.DEVICE_IN_PROXY:
+                aidl.type = AudioDeviceType.IN_AFE_PROXY;
+                break;
+            case AudioSystem.DEVICE_OUT_PROXY:
+                aidl.type = AudioDeviceType.OUT_AFE_PROXY;
+                break;
+            case AudioSystem.DEVICE_IN_USB_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_USB_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_HDMI_ARC:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
+                break;
+            case AudioSystem.DEVICE_OUT_HDMI_ARC:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
+                break;
+            case AudioSystem.DEVICE_IN_HDMI_EARC:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
+                break;
+            case AudioSystem.DEVICE_OUT_HDMI_EARC:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
+                break;
+            case AudioSystem.DEVICE_IN_BLE_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_OUT_BLE_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_IN_DEFAULT:
+                aidl.type = AudioDeviceType.IN_DEFAULT;
+                break;
+            case AudioSystem.DEVICE_OUT_DEFAULT:
+                aidl.type = AudioDeviceType.OUT_DEFAULT;
+                break;
+            default:
+                aidl.type = AudioDeviceType.NONE;
+        }
+        return aidl;
+    }
+
     private static native int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(
             Parcel aidl, boolean isInput);
     private static native Parcel legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index d8f48c2..20d711c 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -103,6 +103,7 @@
     private int mDeviceType;
     private String mHostType;
     private boolean mSkipThumbForHost = false;
+    private volatile boolean mHostIsWindows = false;
 
     private MtpServer mServer;
     private MtpStorageManager mManager;
@@ -358,7 +359,7 @@
     }
 
     public void addStorage(StorageVolume storage) {
-        MtpStorage mtpStorage = mManager.addMtpStorage(storage);
+        MtpStorage mtpStorage = mManager.addMtpStorage(storage, () -> mHostIsWindows);
         mStorageMap.put(storage.getPath(), mtpStorage);
         if (mServer != null) {
             mServer.addStorage(mtpStorage);
@@ -413,6 +414,7 @@
         }
         mHostType = "";
         mSkipThumbForHost = false;
+        mHostIsWindows = false;
     }
 
     @VisibleForNative
@@ -736,10 +738,12 @@
                         : MtpConstants.RESPONSE_GENERAL_ERROR);
             case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
                 mHostType = stringValue;
+                Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+                        + "=" + stringValue);
                 if (stringValue.startsWith("Android/")) {
-                    Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
-                            + "=" + stringValue);
                     mSkipThumbForHost = true;
+                } else if (stringValue.startsWith("Windows/")) {
+                    mHostIsWindows = true;
                 }
                 return MtpConstants.RESPONSE_OK;
         }
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 88c32a3..a3754e90 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -19,6 +19,8 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.storage.StorageVolume;
 
+import java.util.function.Supplier;
+
 /**
  * This class represents a storage unit on an MTP device.
  * Used only for MTP support in USB responder mode.
@@ -33,14 +35,16 @@
     private final boolean mRemovable;
     private final long mMaxFileSize;
     private final String mVolumeName;
+    private final Supplier<Boolean> mIsHostWindows;
 
-    public MtpStorage(StorageVolume volume, int storageId) {
+    public MtpStorage(StorageVolume volume, int storageId, Supplier<Boolean> isHostWindows) {
         mStorageId = storageId;
         mPath = volume.getPath();
         mDescription = volume.getDescription(null);
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
         mVolumeName = volume.getMediaStoreVolumeName();
+        mIsHostWindows = isHostWindows;
     }
 
     /**
@@ -93,4 +97,13 @@
     public String getVolumeName() {
         return mVolumeName;
     }
+
+    /**
+     * Returns true if the mtp host of this storage is Windows.
+     *
+     * @return is host Windows
+     */
+    public boolean isHostWindows() {
+        return mIsHostWindows.get();
+    }
 }
diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java
index 0bede0d..e9426cf 100644
--- a/media/java/android/mtp/MtpStorageManager.java
+++ b/media/java/android/mtp/MtpStorageManager.java
@@ -18,7 +18,11 @@
 
 import android.media.MediaFile;
 import android.os.FileObserver;
+import android.os.SystemProperties;
 import android.os.storage.StorageVolume;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -35,6 +39,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of
@@ -199,7 +204,38 @@
         }
 
         public long getSize() {
-            return mIsDir ? 0 : getPath().toFile().length();
+            return mIsDir ? 0 : maybeApplyTranscodeLengthWorkaround(getPath().toFile().length());
+        }
+
+        private long maybeApplyTranscodeLengthWorkaround(long length) {
+            // Windows truncates transferred files to the size advertised in the object property.
+            if (mStorage.isHostWindows() && isTranscodeMtpEnabled() && isFileTranscodeSupported()) {
+                // If the file supports transcoding, we double the returned size to accommodate
+                // the increase in size from transcoding to AVC. This is the same heuristic
+                // applied in the FUSE daemon (MediaProvider).
+                return length * 2;
+            }
+            return length;
+        }
+
+        private boolean isTranscodeMtpEnabled() {
+            return SystemProperties.getBoolean("sys.fuse.transcode_mtp", false);
+        }
+
+        private boolean isFileTranscodeSupported() {
+            // Check if the file supports transcoding by reading the |st_nlinks| struct stat
+            // field. This will be > 1 if the file supports transcoding. The FUSE daemon
+            // sets the field accordingly to enable the MTP stack workaround some Windows OS
+            // MTP client bug where they ignore the size returned as part of getting the MTP
+            // object, see MtpServer#doGetObject.
+            final Path path = getPath();
+            try {
+                StructStat stat = Os.stat(path.toString());
+                return stat.st_nlink > 1;
+            } catch (ErrnoException e) {
+                Log.w(TAG, "Failed to stat path: " + getPath() + ". Ignoring transcoding.");
+                return false;
+            }
         }
 
         public Path getPath() {
@@ -420,10 +456,12 @@
      * @param volume Storage to add.
      * @return the associated MtpStorage
      */
-    public synchronized MtpStorage addMtpStorage(StorageVolume volume) {
+    public synchronized MtpStorage addMtpStorage(StorageVolume volume,
+                                                 Supplier<Boolean> isHostWindows) {
         int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
-        MtpStorage storage = new MtpStorage(volume, storageId);
-        MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true);
+        MtpStorage storage = new MtpStorage(volume, storageId, isHostWindows);
+        MtpObject root = new MtpObject(storage.getPath(), storageId, storage, /* parent= */ null,
+                                       /* isDir= */ true);
         mRoots.put(storageId, root);
         return storage;
     }
diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
index abdc7e5..a6a5568 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
@@ -160,10 +160,11 @@
                 Log.d(TAG, "sendObjectInfoChanged: " + id);
                 objectsInfoChanged.add(id);
             }
-        }, null);
+        }, /* subdirectories= */ null);
 
-        mainMtpStorage = manager.addMtpStorage(mainStorage);
-        secondaryMtpStorage = manager.addMtpStorage(secondaryStorage);
+        mainMtpStorage = manager.addMtpStorage(mainStorage, /* isHostWindows= */ () -> false);
+        secondaryMtpStorage = manager.addMtpStorage(secondaryStorage,
+                                                    /* isHostWindows= */ () -> false);
     }
 
     @After
diff --git a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
index 414de89..0957390 100644
--- a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
+++ b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
@@ -16,8 +16,18 @@
 
 package android.media.audio.common;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
 import android.media.AudioAttributes;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
+import android.media.AudioProfile;
 import android.media.AudioSystem;
 import android.media.AudioTrack;
 import android.media.MediaFormat;
@@ -25,11 +35,12 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import static org.junit.Assert.*;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+
 /**
  * Unit tests for AidlConversion utilities.
  *
@@ -417,10 +428,102 @@
                 () -> AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(sInvalidValue));
     }
 
+    @Test
+    public void testAudioDescriptorConversion_Default() {
+        ExtraAudioDescriptor aidl = createDefaultDescriptor();
+        AudioDescriptor audioDescriptor =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
+        assertEquals(AudioDescriptor.STANDARD_NONE, audioDescriptor.getStandard());
+        assertEquals(
+                AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, audioDescriptor.getEncapsulationType());
+        assertTrue(Arrays.equals(new byte[]{}, audioDescriptor.getDescriptor()));
+
+        ExtraAudioDescriptor reconstructedExtraDescriptor =
+                AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
+        assertEquals(aidl, reconstructedExtraDescriptor);
+    }
+
+    @Test
+    public void testAudioDescriptorConversion() {
+        ExtraAudioDescriptor aidl = createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A});
+        AudioDescriptor audioDescriptor =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
+        assertEquals(AudioDescriptor.STANDARD_EDID, audioDescriptor.getStandard());
+        assertEquals(AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937,
+                audioDescriptor.getEncapsulationType());
+        assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A}, audioDescriptor.getDescriptor()));
+
+        ExtraAudioDescriptor reconstructedExtraDescriptor =
+                AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
+        assertEquals(aidl, reconstructedExtraDescriptor);
+    }
+
+    @Test
+    public void testAudioDeviceAttributesConversion_Default() {
+        AudioDeviceAttributes attributes =
+                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_DEFAULT, "myAddress");
+        AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
+        assertEquals("", port.name);
+        assertEquals(0, port.extraAudioDescriptors.length);
+        assertEquals("myAddress", port.ext.getDevice().device.address.getId());
+        assertEquals("", port.ext.getDevice().device.type.connection);
+        assertEquals(AudioDeviceType.OUT_DEFAULT, port.ext.getDevice().device.type.type);
+    }
+
+    @Test
+    public void testAudioDeviceAttributesConversion() {
+        AudioDescriptor audioDescriptor1 =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+                        createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A}));
+
+        AudioDescriptor audioDescriptor2 =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+                        createDefaultDescriptor());
+
+        AudioDeviceAttributes attributes =
+                new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
+                        AudioDeviceInfo.TYPE_HDMI_ARC, "myAddress", "myName", new ArrayList<>(),
+                        new ArrayList<>(Arrays.asList(audioDescriptor1, audioDescriptor2)));
+        AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(
+                attributes);
+        assertEquals("myName", port.name);
+        assertEquals(2, port.extraAudioDescriptors.length);
+        assertEquals(AudioStandard.EDID, port.extraAudioDescriptors[0].standard);
+        assertEquals(AudioEncapsulationType.IEC61937,
+                port.extraAudioDescriptors[0].encapsulationType);
+        assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A},
+                port.extraAudioDescriptors[0].audioDescriptor));
+        assertEquals(AudioStandard.NONE, port.extraAudioDescriptors[1].standard);
+        assertEquals(AudioEncapsulationType.NONE,
+                port.extraAudioDescriptors[1].encapsulationType);
+        assertTrue(Arrays.equals(new byte[]{},
+                port.extraAudioDescriptors[1].audioDescriptor));
+        assertEquals("myAddress", port.ext.getDevice().device.address.getId());
+        assertEquals(AudioDeviceDescription.CONNECTION_HDMI_ARC,
+                port.ext.getDevice().device.type.connection);
+        assertEquals(AudioDeviceType.OUT_DEVICE, port.ext.getDevice().device.type.type);
+    }
+
     private static AudioFormatDescription createPcm16FormatAidl() {
         final AudioFormatDescription aidl = new AudioFormatDescription();
         aidl.type = AudioFormatType.PCM;
         aidl.pcm = PcmType.INT_16_BIT;
         return aidl;
     }
+
+    private static ExtraAudioDescriptor createDefaultDescriptor() {
+        ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+        extraDescriptor.standard = AudioStandard.NONE;
+        extraDescriptor.encapsulationType = AudioEncapsulationType.NONE;
+        extraDescriptor.audioDescriptor = new byte[]{};
+        return extraDescriptor;
+    }
+
+    private static ExtraAudioDescriptor createEncapsulationDescriptor(byte[] audioDescriptor) {
+        ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+        extraDescriptor.standard = AudioStandard.EDID;
+        extraDescriptor.encapsulationType = AudioEncapsulationType.IEC61937;
+        extraDescriptor.audioDescriptor = audioDescriptor;
+        return extraDescriptor;
+    }
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
index 0f21e55..512fbce 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
@@ -16,6 +16,9 @@
 
 package android.net.nsd;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
@@ -23,15 +26,22 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Objects;
@@ -278,9 +288,180 @@
     private final SparseArray mListenerMap = new SparseArray();
     private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
     private final Object mMapLock = new Object();
+    // Map of listener key sent by client -> per-network discovery tracker
+    @GuardedBy("mPerNetworkDiscoveryMap")
+    private final ArrayMap<Integer, PerNetworkDiscoveryTracker>
+            mPerNetworkDiscoveryMap = new ArrayMap<>();
 
     private final ServiceHandler mHandler;
 
+    private class PerNetworkDiscoveryTracker {
+        final String mServiceType;
+        final int mProtocolType;
+        final DiscoveryListener mBaseListener;
+        final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners =
+                new ArrayMap<>();
+
+        final NetworkCallback mNetworkCb = new NetworkCallback() {
+            @Override
+            public void onAvailable(@NonNull Network network) {
+                final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener(
+                        network, mBaseListener);
+                mPerNetworkListeners.put(network, wrappedListener);
+                discoverServices(mServiceType, mProtocolType, network, wrappedListener);
+            }
+
+            @Override
+            public void onLost(@NonNull Network network) {
+                final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network);
+                if (listener == null) return;
+                listener.notifyAllServicesLost();
+                // Listener will be removed from map in discovery stopped callback
+                stopServiceDiscovery(listener);
+            }
+        };
+
+        // Accessed from mHandler
+        private boolean mStopRequested;
+
+        public void start(@NonNull NetworkRequest request) {
+            final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+            cm.registerNetworkCallback(request, mNetworkCb, mHandler);
+            mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType));
+        }
+
+        /**
+         * Stop discovery on all networks tracked by this class.
+         *
+         * This will request all underlying listeners to stop, and the last one to stop will call
+         * onDiscoveryStopped or onStopDiscoveryFailed.
+         *
+         * Must be called on the handler thread.
+         */
+        public void requestStop() {
+            mHandler.post(() -> {
+                mStopRequested = true;
+                final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+                cm.unregisterNetworkCallback(mNetworkCb);
+                if (mPerNetworkListeners.size() == 0) {
+                    mBaseListener.onDiscoveryStopped(mServiceType);
+                    return;
+                }
+                for (int i = 0; i < mPerNetworkListeners.size(); i++) {
+                    final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i);
+                    stopServiceDiscovery(listener);
+                }
+            });
+        }
+
+        private PerNetworkDiscoveryTracker(String serviceType, int protocolType,
+                DiscoveryListener baseListener) {
+            mServiceType = serviceType;
+            mProtocolType = protocolType;
+            mBaseListener = baseListener;
+        }
+
+        /**
+         * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a
+         * network is lost.
+         *
+         * Service lost notifications only contain service name, type and network, so only track
+         * that information (Network is known from the listener). This also implements
+         * equals/hashCode for usage in maps.
+         */
+        private class TrackedNsdInfo {
+            private final String mServiceName;
+            private final String mServiceType;
+            TrackedNsdInfo(NsdServiceInfo info) {
+                mServiceName = info.getServiceName();
+                mServiceType = info.getServiceType();
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mServiceName, mServiceType);
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (!(obj instanceof TrackedNsdInfo)) return false;
+                final TrackedNsdInfo other = (TrackedNsdInfo) obj;
+                return Objects.equals(mServiceName, other.mServiceName)
+                        && Objects.equals(mServiceType, other.mServiceType);
+            }
+        }
+
+        private class DelegatingDiscoveryListener implements DiscoveryListener {
+            private final Network mNetwork;
+            private final DiscoveryListener mWrapped;
+            private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>();
+
+            private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) {
+                mNetwork = network;
+                mWrapped = listener;
+            }
+
+            void notifyAllServicesLost() {
+                for (int i = 0; i < mFoundInfo.size(); i++) {
+                    final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i);
+                    final NsdServiceInfo serviceInfo = new NsdServiceInfo(
+                            trackedInfo.mServiceName, trackedInfo.mServiceType);
+                    serviceInfo.setNetwork(mNetwork);
+                    mWrapped.onServiceLost(serviceInfo);
+                }
+            }
+
+            @Override
+            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+                // The delegated listener is used when NsdManager takes care of starting/stopping
+                // discovery on multiple networks. Failure to start on one network is not a global
+                // failure to be reported up, as other networks may succeed: just log.
+                Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork
+                        + " with code " + errorCode);
+                mPerNetworkListeners.remove(mNetwork);
+            }
+
+            @Override
+            public void onDiscoveryStarted(String serviceType) {
+                // Wrapped listener was called upon registration, it is not called for discovery
+                // on each network
+            }
+
+            @Override
+            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+                Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork
+                        + " with code " + errorCode);
+                mPerNetworkListeners.remove(mNetwork);
+                if (mStopRequested && mPerNetworkListeners.size() == 0) {
+                    // Do not report onStopDiscoveryFailed when some underlying listeners failed:
+                    // this does not mean that all listeners did, and onStopDiscoveryFailed is not
+                    // actionable anyway. Just report that discovery stopped.
+                    mWrapped.onDiscoveryStopped(serviceType);
+                }
+            }
+
+            @Override
+            public void onDiscoveryStopped(String serviceType) {
+                mPerNetworkListeners.remove(mNetwork);
+                if (mStopRequested && mPerNetworkListeners.size() == 0) {
+                    mWrapped.onDiscoveryStopped(serviceType);
+                }
+            }
+
+            @Override
+            public void onServiceFound(NsdServiceInfo serviceInfo) {
+                mFoundInfo.add(new TrackedNsdInfo(serviceInfo));
+                mWrapped.onServiceFound(serviceInfo);
+            }
+
+            @Override
+            public void onServiceLost(NsdServiceInfo serviceInfo) {
+                mFoundInfo.remove(new TrackedNsdInfo(serviceInfo));
+                mWrapped.onServiceLost(serviceInfo);
+            }
+        }
+    }
+
     /**
      * Create a new Nsd instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -634,6 +815,14 @@
     }
 
     /**
+     * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null
+     * {@link Network}.
+     */
+    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+        discoverServices(serviceType, protocolType, (Network) null, listener);
+    }
+
+    /**
      * Initiate service discovery to browse for instances of a service type. Service discovery
      * consumes network bandwidth and will continue until the application calls
      * {@link #stopServiceDiscovery}.
@@ -657,11 +846,13 @@
      * @param serviceType The service type being discovered. Examples include "_http._tcp" for
      * http services or "_ipp._tcp" for printers
      * @param protocolType The service discovery protocol
+     * @param network Network to discover services on, or null to discover on all available networks
      * @param listener  The listener notifies of a successful discovery and is used
      * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
      * Cannot be null. Cannot be in use for an active service discovery.
      */
-    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+    public void discoverServices(@NonNull String serviceType, int protocolType,
+            @Nullable Network network, @NonNull DiscoveryListener listener) {
         if (TextUtils.isEmpty(serviceType)) {
             throw new IllegalArgumentException("Service type cannot be empty");
         }
@@ -669,6 +860,7 @@
 
         NsdServiceInfo s = new NsdServiceInfo();
         s.setServiceType(serviceType);
+        s.setNetwork(network);
 
         int key = putListener(listener, s);
         try {
@@ -679,6 +871,67 @@
     }
 
     /**
+     * Initiate service discovery to browse for instances of a service type. Service discovery
+     * consumes network bandwidth and will continue until the application calls
+     * {@link #stopServiceDiscovery}.
+     *
+     * <p> The function call immediately returns after sending a request to start service
+     * discovery to the framework. The application is notified of a success to initiate
+     * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
+     * through {@link DiscoveryListener#onStartDiscoveryFailed}.
+     *
+     * <p> Upon successful start, application is notified when a service is found with
+     * {@link DiscoveryListener#onServiceFound} or when a service is lost with
+     * {@link DiscoveryListener#onServiceLost}.
+     *
+     * <p> Upon failure to start, service discovery is not active and application does
+     * not need to invoke {@link #stopServiceDiscovery}
+     *
+     * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
+     * service type is no longer required, and/or whenever the application is paused or
+     * stopped.
+     *
+     * <p> During discovery, new networks may connect or existing networks may disconnect - for
+     * example if wifi is reconnected. When a service was found on a network that disconnects,
+     * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that
+     * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called
+     * for services found on that network. Applications that do not want to track networks
+     * themselves are encouraged to use this method instead of other overloads of
+     * {@code discoverServices}, as they will receive proper notifications when a service becomes
+     * available or unavailable due to network changes.
+     *
+     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
+     * http services or "_ipp._tcp" for printers
+     * @param protocolType The service discovery protocol
+     * @param networkRequest Request specifying networks that should be considered when discovering
+     * @param listener  The listener notifies of a successful discovery and is used
+     * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
+     * Cannot be null. Cannot be in use for an active service discovery.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    public void discoverServices(@NonNull String serviceType, int protocolType,
+            @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) {
+        if (TextUtils.isEmpty(serviceType)) {
+            throw new IllegalArgumentException("Service type cannot be empty");
+        }
+        Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null");
+        checkProtocol(protocolType);
+
+        NsdServiceInfo s = new NsdServiceInfo();
+        s.setServiceType(serviceType);
+
+        final int baseListenerKey = putListener(listener, s);
+
+        final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker(
+                serviceType, protocolType, listener);
+
+        synchronized (mPerNetworkDiscoveryMap) {
+            mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo);
+            discoveryInfo.start(networkRequest);
+        }
+    }
+
+    /**
      * Stop service discovery initiated with {@link #discoverServices}.  An active service
      * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
      * and it stays active until the application invokes a stop service discovery. A successful
@@ -696,6 +949,14 @@
      */
     public void stopServiceDiscovery(DiscoveryListener listener) {
         int id = getListenerKey(listener);
+        // If this is a PerNetworkDiscovery request, handle it as such
+        synchronized (mPerNetworkDiscoveryMap) {
+            final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id);
+            if (info != null) {
+                info.requestStop();
+                return;
+            }
+        }
         try {
             mService.stopDiscovery(id);
         } catch (RemoteException e) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
index 0946499..8506db1 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
@@ -17,7 +17,9 @@
 package android.net.nsd;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.net.Network;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -49,6 +51,9 @@
 
     private int mPort;
 
+    @Nullable
+    private Network mNetwork;
+
     public NsdServiceInfo() {
     }
 
@@ -307,18 +312,37 @@
         return txtRecord;
     }
 
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
+    /**
+     * Get the network where the service can be found.
+     *
+     * This is never null if this {@link NsdServiceInfo} was obtained from
+     * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}.
+     */
+    @Nullable
+    public Network getNetwork() {
+        return mNetwork;
+    }
 
+    /**
+     * Set the network where the service can be found.
+     * @param network The network, or null to search for, or to announce, the service on all
+     *                connected networks.
+     */
+    public void setNetwork(@Nullable Network network) {
+        mNetwork = network;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
         sb.append("name: ").append(mServiceName)
                 .append(", type: ").append(mServiceType)
                 .append(", host: ").append(mHost)
-                .append(", port: ").append(mPort);
+                .append(", port: ").append(mPort)
+                .append(", network: ").append(mNetwork);
 
         byte[] txtRecord = getTxtRecord();
-        if (txtRecord != null) {
-            sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
-        }
+        sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
         return sb.toString();
     }
 
@@ -352,6 +376,8 @@
             }
             dest.writeString(key);
         }
+
+        dest.writeParcelable(mNetwork, 0);
     }
 
     /** Implement the Parcelable interface */
@@ -381,6 +407,7 @@
                     }
                     info.mTxtRecord.put(in.readString(), valueArray);
                 }
+                info.mNetwork = in.readParcelable(null, Network.class);
                 return info;
             }
 
diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
index 497107d..ddf6d2c 100644
--- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
@@ -19,6 +19,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
 import android.net.nsd.INsdManager;
 import android.net.nsd.INsdManagerCallback;
 import android.net.nsd.INsdServiceConnector;
@@ -44,6 +47,9 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
@@ -60,6 +66,7 @@
 
     private static final boolean DBG = true;
     private static final long CLEANUP_DELAY_MS = 10000;
+    private static final int IFACE_IDX_ANY = 0;
 
     private final Context mContext;
     private final NsdStateMachine mNsdStateMachine;
@@ -297,7 +304,7 @@
 
                         maybeStartDaemon();
                         id = getUniqueId();
-                        if (discoverServices(id, args.serviceInfo.getServiceType())) {
+                        if (discoverServices(id, args.serviceInfo)) {
                             if (DBG) {
                                 Log.d(TAG, "Discover " + msg.arg2 + " " + id
                                         + args.serviceInfo.getServiceType());
@@ -430,13 +437,38 @@
                 }
                 switch (code) {
                     case NativeResponseCode.SERVICE_FOUND:
-                        /* NNN uniqueId serviceName regType domain */
+                        /* NNN uniqueId serviceName regType domain interfaceIdx netId */
                         servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
+                        final int foundNetId;
+                        try {
+                            foundNetId = Integer.parseInt(cooked[6]);
+                        } catch (NumberFormatException e) {
+                            Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
+                            break;
+                        }
+                        if (foundNetId == 0L) {
+                            // Ignore services that do not have a Network: they are not usable
+                            // by apps, as they would need privileged permissions to use
+                            // interfaces that do not have an associated Network.
+                            break;
+                        }
+                        servInfo.setNetwork(new Network(foundNetId));
                         clientInfo.onServiceFound(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_LOST:
-                        /* NNN uniqueId serviceName regType domain */
+                        /* NNN uniqueId serviceName regType domain interfaceIdx netId */
+                        final int lostNetId;
+                        try {
+                            lostNetId = Integer.parseInt(cooked[6]);
+                        } catch (NumberFormatException e) {
+                            Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
+                            break;
+                        }
                         servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
+                        // The network could be null if it was torn down when the service is lost
+                        // TODO: avoid returning null in that case, possibly by remembering found
+                        // services on the same interface index and their network at the time
+                        servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId));
                         clientInfo.onServiceLost(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
@@ -461,7 +493,7 @@
                         /* NNN regId errorCode */
                         break;
                     case NativeResponseCode.SERVICE_RESOLVED:
-                        /* NNN resolveId fullName hostName port txtlen txtdata */
+                        /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */
                         int index = 0;
                         while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
                             if (cooked[2].charAt(index) == '\\') {
@@ -473,6 +505,7 @@
                             Log.e(TAG, "Invalid service found " + raw);
                             break;
                         }
+
                         String name = cooked[2].substring(0, index);
                         String rest = cooked[2].substring(index);
                         String type = rest.replace(".local.", "");
@@ -483,12 +516,13 @@
                         clientInfo.mResolvedService.setServiceType(type);
                         clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
                         clientInfo.mResolvedService.setTxtRecords(cooked[6]);
+                        // Network will be added after SERVICE_GET_ADDR_SUCCESS
 
                         stopResolveService(id);
                         removeRequestMap(clientId, id, clientInfo);
 
                         int id2 = getUniqueId();
-                        if (getAddrInfo(id2, cooked[3])) {
+                        if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) {
                             storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
                         } else {
                             clientInfo.onResolveServiceFailed(
@@ -513,12 +547,31 @@
                                 clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         break;
                     case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
-                        /* NNN resolveId hostname ttl addr */
+                        /* NNN resolveId hostname ttl addr interfaceIdx netId */
+                        Network network = null;
                         try {
-                            clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
+                            final int netId = Integer.parseInt(cooked[6]);
+                            network = netId == 0L ? null : new Network(netId);
+                        } catch (NumberFormatException e) {
+                            Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e);
+                        }
+
+                        InetAddress serviceHost = null;
+                        try {
+                            serviceHost = InetAddress.getByName(cooked[4]);
+                        } catch (UnknownHostException e) {
+                            Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
+                        }
+
+                        // If the resolved service is on an interface without a network, consider it
+                        // as a failure: it would not be usable by apps as they would need
+                        // privileged permissions.
+                        if (network != null && serviceHost != null) {
+                            clientInfo.mResolvedService.setHost(serviceHost);
+                            clientInfo.mResolvedService.setNetwork(network);
                             clientInfo.onResolveServiceSucceeded(
                                     clientId, clientInfo.mResolvedService);
-                        } catch (java.net.UnknownHostException e) {
+                        } else {
                             clientInfo.onResolveServiceFailed(
                                     clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
@@ -815,8 +868,15 @@
         return mDaemon.execute("update", regId, t.size(), t.getRawData());
     }
 
-    private boolean discoverServices(int discoveryId, String serviceType) {
-        return mDaemon.execute("discover", discoveryId, serviceType);
+    private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) {
+        final Network network = serviceInfo.getNetwork();
+        final int discoverInterface = getNetworkInterfaceIndex(network);
+        if (network != null && discoverInterface == IFACE_IDX_ANY) {
+            Log.e(TAG, "Interface to discover service on not found");
+            return false;
+        }
+        return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(),
+                discoverInterface);
     }
 
     private boolean stopServiceDiscovery(int discoveryId) {
@@ -824,17 +884,61 @@
     }
 
     private boolean resolveService(int resolveId, NsdServiceInfo service) {
-        String name = service.getServiceName();
-        String type = service.getServiceType();
-        return mDaemon.execute("resolve", resolveId, name, type, "local.");
+        final String name = service.getServiceName();
+        final String type = service.getServiceType();
+        final Network network = service.getNetwork();
+        final int resolveInterface = getNetworkInterfaceIndex(network);
+        if (network != null && resolveInterface == IFACE_IDX_ANY) {
+            Log.e(TAG, "Interface to resolve service on not found");
+            return false;
+        }
+        return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface);
+    }
+
+    /**
+     * Guess the interface to use to resolve or discover a service on a specific network.
+     *
+     * This is an imperfect guess, as for example the network may be gone or not yet fully
+     * registered. This is fine as failing is correct if the network is gone, and a client
+     * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
+     * this is to support the legacy mdnsresponder implementation, which historically resolved
+     * services on an unspecified network.
+     */
+    private int getNetworkInterfaceIndex(Network network) {
+        if (network == null) return IFACE_IDX_ANY;
+
+        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm == null) {
+            Log.wtf(TAG, "No ConnectivityManager for resolveService");
+            return IFACE_IDX_ANY;
+        }
+        final LinkProperties lp = cm.getLinkProperties(network);
+        if (lp == null) return IFACE_IDX_ANY;
+
+        // Only resolve on non-stacked interfaces
+        final NetworkInterface iface;
+        try {
+            iface = NetworkInterface.getByName(lp.getInterfaceName());
+        } catch (SocketException e) {
+            Log.e(TAG, "Error querying interface", e);
+            return IFACE_IDX_ANY;
+        }
+
+        if (iface == null) {
+            Log.e(TAG, "Interface not found: " + lp.getInterfaceName());
+            return IFACE_IDX_ANY;
+        }
+
+        return iface.getIndex();
     }
 
     private boolean stopResolveService(int resolveId) {
         return mDaemon.execute("stop-resolve", resolveId);
     }
 
-    private boolean getAddrInfo(int resolveId, String hostname) {
-        return mDaemon.execute("getaddrinfo", resolveId, hostname);
+    private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) {
+        // interfaceIdx is always obtained (as string) from the service resolved callback
+        return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx);
     }
 
     private boolean stopGetAddrInfo(int resolveId) {
diff --git a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
index c8ddcc8..6940c39 100644
--- a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
+++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
@@ -27,14 +27,14 @@
         android:layout_gravity="center">
         <ImageView
             android:id="@+id/user_photo"
-            android:layout_width="@dimen/user_photo_size_in_profile_info_dialog"
-            android:layout_height="@dimen/user_photo_size_in_profile_info_dialog"
+            android:layout_width="@dimen/user_photo_size_in_user_info_dialog"
+            android:layout_height="@dimen/user_photo_size_in_user_info_dialog"
             android:contentDescription="@string/user_image_photo_selector"
             android:scaleType="fitCenter"/>
         <ImageView
             android:id="@+id/add_a_photo_icon"
-            android:layout_width="@dimen/add_a_photo_icon_size_in_profile_info_dialog"
-            android:layout_height="@dimen/add_a_photo_icon_size_in_profile_info_dialog"
+            android:layout_width="@dimen/add_a_photo_icon_size_in_user_info_dialog"
+            android:layout_height="@dimen/add_a_photo_icon_size_in_user_info_dialog"
             android:src="@drawable/add_a_photo_circled"
             android:layout_gravity="bottom|right" />
     </FrameLayout>
@@ -42,7 +42,7 @@
     <EditText
         android:id="@+id/user_name"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="@dimen/user_name_height_in_user_info_dialog"
         android:layout_gravity="center"
         android:minWidth="200dp"
         android:layout_marginStart="6dp"
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 120df76..e1bd9f70 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -99,8 +99,9 @@
     <dimen name="update_user_photo_popup_min_width">300dp</dimen>
 
     <dimen name="add_a_photo_circled_padding">6dp</dimen>
-    <dimen name="user_photo_size_in_profile_info_dialog">112dp</dimen>
-    <dimen name="add_a_photo_icon_size_in_profile_info_dialog">32dp</dimen>
+    <dimen name="user_photo_size_in_user_info_dialog">112dp</dimen>
+    <dimen name="add_a_photo_icon_size_in_user_info_dialog">32dp</dimen>
+    <dimen name="user_name_height_in_user_info_dialog">48sp</dimen>
 
     <integer name="avatar_picker_columns">3</integer>
     <dimen name="avatar_size_in_picker">96dp</dimen>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index db6d41e..e203cba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -144,20 +144,20 @@
     * @hide
     */
     public boolean connect(BluetoothDevice device) {
-       if (mService == null) {
-           return false;
-       }
-       return mService.connect(device);
+        if (mService == null) {
+            return false;
+        }
+        return mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
     }
 
     /*
     * @hide
     */
     public boolean disconnect(BluetoothDevice device) {
-       if (mService == null) {
-           return false;
-       }
-       return mService.disconnect(device);
+        if (mService == null) {
+            return false;
+        }
+        return mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
     }
 
     public int getConnectionStatus(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index a000c09..d179b82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -528,7 +528,18 @@
         if (flattenedString.indexOf('/') < 0) {
             flattenedString = serviceInfo.packageName + "/" + flattenedString;
         }
-        return ComponentName.unflattenFromString(flattenedString);
+
+        ComponentName cn = ComponentName.unflattenFromString(flattenedString);
+
+        if (cn == null) return null;
+        if (!cn.getPackageName().equals(serviceInfo.packageName)) {
+            Log.w(TAG,
+                    "Inconsistent package name in component: " + cn.getPackageName()
+                            + ", should be: " + serviceInfo.packageName);
+            return null;
+        }
+
+        return cn;
     }
 
     private static DreamMetadata getDreamMetadata(PackageManager pm, ResolveInfo resolveInfo) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 00b5f50..a6bfc408b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -84,6 +84,7 @@
         Settings.System.RING_VIBRATION_INTENSITY,
         Settings.System.HAPTIC_FEEDBACK_INTENSITY,
         Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY,
+        Settings.System.HAPTIC_FEEDBACK_ENABLED,
         Settings.System.DISPLAY_COLOR_MODE_VENDOR_HINT, // must precede DISPLAY_COLOR_MODE
         Settings.System.DISPLAY_COLOR_MODE,
         Settings.System.ALARM_ALERT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 6bcb769..06712cc 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -124,6 +124,7 @@
         VALIDATORS.put(System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+        VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
         VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 0223c60..240ca36 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -657,7 +657,10 @@
                 }
                 val runnable = if (action.actionIntent != null) {
                     Runnable {
-                        if (action.isAuthenticationRequired()) {
+                        if (action.actionIntent.isActivity) {
+                            activityStarter.startPendingIntentDismissingKeyguard(
+                                action.actionIntent)
+                        } else if (action.isAuthenticationRequired()) {
                             activityStarter.dismissKeyguardThenExecute({
                                 var result = sendPendingIntent(action.actionIntent)
                                 result
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5302188..4a7606c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -22,6 +22,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -33,7 +34,6 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.Parcelable;
@@ -57,6 +57,7 @@
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.util.drawable.DrawableSize;
 
 import java.text.NumberFormat;
 import java.util.Arrays;
@@ -84,16 +85,6 @@
     public static final int STATE_DOT = 1;
     public static final int STATE_HIDDEN = 2;
 
-    /**
-     * Maximum allowed byte count for an icon bitmap
-     * @see android.graphics.RecordingCanvas.MAX_BITMAP_SIZE
-     */
-    private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
-    /**
-     * Maximum allowed width or height for an icon drawable, if we can't get byte count
-     */
-    private static final int MAX_IMAGE_SIZE = 5000;
-
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -390,21 +381,6 @@
             return false;
         }
 
-        if (drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() != null) {
-            // If it's a bitmap we can check the size directly
-            int byteCount = ((BitmapDrawable) drawable).getBitmap().getByteCount();
-            if (byteCount > MAX_BITMAP_SIZE) {
-                Log.w(TAG, "Drawable is too large (" + byteCount + " bytes) " + mIcon);
-                return false;
-            }
-        } else if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE
-                || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) {
-            // Otherwise, check dimensions
-            Log.w(TAG, "Drawable is too large (" + drawable.getIntrinsicWidth() + "x"
-                    + drawable.getIntrinsicHeight() + ") " + mIcon);
-            return false;
-        }
-
         if (withClear) {
             setImageDrawable(null);
         }
@@ -432,7 +408,7 @@
      * @return Drawable for this item, or null if the package or item could not
      *         be found
      */
-    public static Drawable getIcon(Context sysuiContext,
+    private Drawable getIcon(Context sysuiContext,
             Context context, StatusBarIcon statusBarIcon) {
         int userId = statusBarIcon.user.getIdentifier();
         if (userId == UserHandle.USER_ALL) {
@@ -446,6 +422,16 @@
                 typedValue, true);
         float scaleFactor = typedValue.getFloat();
 
+        // We downscale the loaded drawable to reasonable size to protect against applications
+        // using too much memory. The size can be tweaked in config.xml. Drawables
+        // that are already sized properly won't be touched.
+        boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+        Resources res = sysuiContext.getResources();
+        int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
+                                ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
+                                : com.android.internal.R.dimen.notification_small_icon_size);
+        icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+
         // No need to scale the icon, so return it as is.
         if (scaleFactor == 1.f) {
             return icon;
diff --git a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
new file mode 100644
index 0000000..b506808
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
@@ -0,0 +1,123 @@
+package com.android.systemui.util.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedImageDrawable
+import android.graphics.drawable.AnimatedRotateDrawable
+import android.graphics.drawable.AnimatedStateListDrawable
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.util.Log
+import androidx.annotation.Px
+import com.android.systemui.util.traceSection
+
+class DrawableSize {
+
+    companion object {
+
+        const val TAG = "SysUiDrawableSize"
+
+        /**
+         * Downscales passed Drawable to set maximum width and height. This will only
+         * be done for Drawables that can be downscaled non-destructively - e.g. animated
+         * and stateful drawables will no be downscaled.
+         *
+         * Downscaling will keep the aspect ratio.
+         * This method will not touch drawables that already fit into size specification.
+         *
+         * @param resources Resources on which to base the density of resized drawable.
+         * @param drawable Drawable to downscale.
+         * @param maxWidth Maximum width of the downscaled drawable.
+         * @param maxHeight Maximum height of the downscaled drawable.
+         *
+         * @return returns downscaled drawable if it's possible to downscale it or original if it's
+         *         not.
+         */
+        @JvmStatic
+        fun downscaleToSize(
+            res: Resources,
+            drawable: Drawable,
+            @Px maxWidth: Int,
+            @Px maxHeight: Int
+        ): Drawable {
+            traceSection("DrawableSize#downscaleToSize") {
+                // Bitmap drawables can contain big bitmaps as their content while sneaking it past
+                // us using density scaling. Inspect inside the Bitmap drawables for actual bitmap
+                // size for those.
+                val originalWidth = (drawable as? BitmapDrawable)?.bitmap?.width
+                                    ?: drawable.intrinsicWidth
+                val originalHeight = (drawable as? BitmapDrawable)?.bitmap?.height
+                                    ?: drawable.intrinsicHeight
+
+                // Don't touch drawable if we can't resolve sizes for whatever reason.
+                if (originalWidth <= 0 || originalHeight <= 0) {
+                    return drawable
+                }
+
+                // Do not touch drawables that are already within bounds.
+                if (originalWidth < maxWidth && originalHeight < maxHeight) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Not resizing $originalWidth x $originalHeight" + " " +
+                                "to $maxWidth x $maxHeight")
+                    }
+
+                    return drawable
+                }
+
+                if (!isSimpleBitmap(drawable)) {
+                    return drawable
+                }
+
+                val scaleWidth = maxWidth.toFloat() / originalWidth.toFloat()
+                val scaleHeight = maxHeight.toFloat() / originalHeight.toFloat()
+                val scale = minOf(scaleHeight, scaleWidth)
+
+                val width = (originalWidth * scale).toInt()
+                val height = (originalHeight * scale).toInt()
+
+                if (width <= 0 || height <= 0) {
+                    Log.w(TAG, "Attempted to resize ${drawable.javaClass.simpleName} " +
+                            "from $originalWidth x $originalHeight to invalid $width x $height.")
+                    return drawable
+                }
+
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Resizing large drawable (${drawable.javaClass.simpleName}) " +
+                            "from $originalWidth x $originalHeight to $width x $height")
+                }
+
+                // We want to keep existing config if it's more efficient than 32-bit RGB.
+                val config = (drawable as? BitmapDrawable)?.bitmap?.config
+                        ?: Bitmap.Config.ARGB_8888
+                val scaledDrawableBitmap = Bitmap.createBitmap(width, height, config)
+                val canvas = Canvas(scaledDrawableBitmap)
+
+                val originalBounds = drawable.bounds
+                drawable.setBounds(0, 0, width, height)
+                drawable.draw(canvas)
+                drawable.bounds = originalBounds
+
+                return BitmapDrawable(res, scaledDrawableBitmap)
+            }
+        }
+
+        private fun isSimpleBitmap(drawable: Drawable): Boolean {
+            return !(drawable.isStateful || isAnimated(drawable))
+        }
+
+        private fun isAnimated(drawable: Drawable): Boolean {
+            if (drawable is Animatable || drawable is Animatable2) {
+                return true
+            }
+
+            return drawable is AnimatedImageDrawable ||
+                drawable is AnimatedRotateDrawable ||
+                drawable is AnimatedStateListDrawable ||
+                drawable is AnimatedVectorDrawable
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 85ea52b..d13451d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
@@ -37,6 +39,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
@@ -130,7 +133,12 @@
         Icon icon = Icon.createWithBitmap(largeBitmap);
         StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
                 icon, 0, 0, "");
-        assertFalse(mIconView.set(largeIcon));
+        assertTrue(mIconView.set(largeIcon));
+
+        // The view should downscale the bitmap.
+        BitmapDrawable drawable = (BitmapDrawable) mIconView.getDrawable();
+        assertThat(drawable.getBitmap().getWidth()).isLessThan(1000);
+        assertThat(drawable.getBitmap().getHeight()).isLessThan(1000);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
new file mode 100644
index 0000000..ac357ea
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -0,0 +1,73 @@
+package com.android.systemui.util.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ShapeDrawable
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class DrawableSizeTest : SysuiTestCase() {
+
+    lateinit var resources: Resources
+
+    @Before
+    fun setUp() {
+        resources = context.resources
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableZeroSize_unchanged() {
+        val drawable = ShapeDrawable()
+        val result = DrawableSize.downscaleToSize(resources, drawable, 100, 100)
+        assertThat(result).isSameInstanceAs(drawable)
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableSmallerThanRequirement_unchanged() {
+        val drawable = BitmapDrawable(resources,
+                Bitmap.createBitmap(
+                        resources.displayMetrics,
+                        150,
+                        150,
+                        Bitmap.Config.ARGB_8888
+                )
+        )
+        val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
+        assertThat(result).isSameInstanceAs(drawable)
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableLargerThanRequirementWithDensity_resized() {
+        // This bitmap would actually fail to resize if the method doesn't check for
+        // bitmap dimensions inside drawable.
+        val drawable = BitmapDrawable(resources,
+                Bitmap.createBitmap(
+                        resources.displayMetrics,
+                        150,
+                        75,
+                        Bitmap.Config.ARGB_8888
+                )
+        )
+
+        val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
+        assertThat(result).isNotSameInstanceAs(drawable)
+        assertThat(result.intrinsicWidth).isEqualTo(75)
+        assertThat(result.intrinsicHeight).isEqualTo(37)
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableAnimated_unchanged() {
+        val drawable = resources.getDrawable(android.R.drawable.stat_sys_download,
+                resources.newTheme())
+        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+        assertThat(result).isSameInstanceAs(drawable)
+    }
+}
\ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index bb49ba0..75acf81 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -39,7 +39,6 @@
 
 import java.util.List;
 import java.util.Set;
-import java.util.function.Consumer;
 
 
 /**
@@ -62,7 +61,6 @@
     private final ArraySet<ComponentName> mAllowedActivities;
     @Nullable
     private final ArraySet<ComponentName> mBlockedActivities;
-    private Consumer<ActivityInfo> mActivityBlockedCallback;
 
     @NonNull
     final ArraySet<Integer> mRunningUids = new ArraySet<>();
@@ -83,12 +81,10 @@
             @NonNull ArraySet<UserHandle> allowedUsers,
             @Nullable Set<ComponentName> allowedActivities,
             @Nullable Set<ComponentName> blockedActivities,
-            @NonNull ActivityListener activityListener,
-            @NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+            @NonNull ActivityListener activityListener) {
         mAllowedUsers = allowedUsers;
         mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities);
         mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities);
-        mActivityBlockedCallback = activityBlockedCallback;
         setInterestedWindowFlags(windowFlags, systemWindowFlags);
         mActivityListener = activityListener;
     }
@@ -100,7 +96,6 @@
         for (int i = 0; i < activityCount; i++) {
             final ActivityInfo aInfo = activities.get(i);
             if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
-                mActivityBlockedCallback.accept(aInfo);
                 return false;
             }
         }
@@ -110,11 +105,7 @@
     @Override
     public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
             int systemWindowFlags) {
-        if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
-            mActivityBlockedCallback.accept(activityInfo);
-            return false;
-        }
-        return true;
+        return canContainActivity(activityInfo, windowFlags, systemWindowFlags);
     }
 
     @Override
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 98a5ec1..95b9e58 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -34,8 +34,6 @@
 import android.companion.virtual.VirtualDeviceParams;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.hardware.display.DisplayManager;
@@ -59,7 +57,6 @@
 import android.window.DisplayWindowPolicyController;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.BlockedAppActivity;
 import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
@@ -421,8 +418,7 @@
                             getAllowedUserHandles(),
                             mParams.getAllowedActivities(),
                             mParams.getBlockedActivities(),
-                            createListenerAdapter(displayId),
-                            activityInfo -> onActivityBlocked(displayId, activityInfo));
+                            createListenerAdapter(displayId));
             mWindowPolicyControllers.put(displayId, dwpc);
             return dwpc;
         }
@@ -445,16 +441,6 @@
         }
     }
 
-    private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
-        Intent intent = BlockedAppActivity.createStreamingBlockedIntent(
-                UserHandle.getUserId(activityInfo.applicationInfo.uid), activityInfo,
-                mAssociationInfo.getDisplayName());
-        mContext.startActivityAsUser(
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
-                ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(),
-                mContext.getUser());
-    }
-
     private ArraySet<UserHandle> getAllowedUserHandles() {
         ArraySet<UserHandle> result = new ArraySet<>();
         DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index bcb1be3..940ad73 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -123,6 +123,7 @@
     static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
     static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
             "kill_bg_restricted_cached_idle_settle_time";
+    static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias";
     static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -199,6 +200,7 @@
      * Whether or not to enable the extra delays to service restarts on memory pressure.
      */
     private static final boolean DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE = true;
+    private static final boolean DEFAULT_ENABLE_COMPONENT_ALIAS = false;
     private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = "";
 
     // Flag stored in the DeviceConfig API.
@@ -595,6 +597,12 @@
             DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE;
 
     /**
+     * Whether to enable "component alias" experimental feature. This can only be enabled
+     * on userdebug or eng builds.
+     */
+    volatile boolean mEnableComponentAlias = DEFAULT_ENABLE_COMPONENT_ALIAS;
+
+    /**
      * Defines component aliases. Format
      * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
      */
@@ -831,6 +839,7 @@
                             case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
                                 updateEnableExtraServiceRestartDelayOnMemPressure();
                                 break;
+                            case KEY_ENABLE_COMPONENT_ALIAS:
                             case KEY_COMPONENT_ALIAS_OVERRIDES:
                                 updateComponentAliases();
                                 break;
@@ -1269,11 +1278,15 @@
     }
 
     private void updateComponentAliases() {
+        mEnableComponentAlias = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_ENABLE_COMPONENT_ALIAS,
+                DEFAULT_ENABLE_COMPONENT_ALIAS);
         mComponentAliasOverrides = DeviceConfig.getString(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 KEY_COMPONENT_ALIAS_OVERRIDES,
                 DEFAULT_COMPONENT_ALIAS_OVERRIDES);
-        mService.mComponentAliasResolver.update(mComponentAliasOverrides);
+        mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
     }
 
     private void updateProcessKillTimeout() {
@@ -1512,6 +1525,8 @@
         pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
         pw.print("  "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
         pw.print("="); pw.println(mFgsAllowOptOut);
+        pw.print("  "); pw.print(KEY_ENABLE_COMPONENT_ALIAS);
+        pw.print("="); pw.println(mEnableComponentAlias);
         pw.print("  "); pw.print(KEY_COMPONENT_ALIAS_OVERRIDES);
         pw.print("="); pw.println(mComponentAliasOverrides);
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e2204e2..0310b0f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8066,7 +8066,8 @@
 
             // Load the component aliases.
             t.traceBegin("componentAlias");
-            mComponentAliasResolver.onSystemReady(mConstants.mComponentAliasOverrides);
+            mComponentAliasResolver.onSystemReady(mConstants.mEnableComponentAlias,
+                    mConstants.mComponentAliasOverrides);
             t.traceEnd(); // componentAlias
 
             t.traceEnd(); // PhaseActivityManagerReady
diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java
index 23553a7..aef7a6c 100644
--- a/services/core/java/com/android/server/am/ComponentAliasResolver.java
+++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java
@@ -30,6 +30,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -56,6 +57,8 @@
  * "quick & dirty". For example, to define aliases, we use a regular intent filter and meta-data
  * in the manifest, instead of adding proper tags/attributes to AndroidManifest.xml.
  *
+ * Because it's an experimental feature, it can't be enabled on a user build.
+ *
  * Also, for now, aliases can be defined across any packages, but in the final version, there'll
  * be restrictions:
  * - We probably should only allow either privileged or preinstalled apps.
@@ -78,6 +81,9 @@
     private final Context mContext;
 
     @GuardedBy("mLock")
+    private boolean mEnabledByDeviceConfig;
+
+    @GuardedBy("mLock")
     private boolean mEnabled;
 
     @GuardedBy("mLock")
@@ -141,7 +147,7 @@
     /**
      * Call this on systemRead().
      */
-    public void onSystemReady(String overrides) {
+    public void onSystemReady(boolean enabledByDeviceConfig, String overrides) {
         synchronized (mLock) {
             mPlatformCompat = (PlatformCompat) ServiceManager.getService(
                     Context.PLATFORM_COMPAT_SERVICE);
@@ -149,19 +155,21 @@
                     mCompatChangeListener);
         }
         if (DEBUG) Slog.d(TAG, "Compat listener set.");
-        update(overrides);
+        update(enabledByDeviceConfig, overrides);
     }
 
     /**
      * (Re-)loads aliases from <meta-data> and the device config override.
      */
-    public void update(String overrides) {
+    public void update(boolean enabledByDeviceConfig, String overrides) {
         synchronized (mLock) {
             if (mPlatformCompat == null) {
                 return; // System not ready.
             }
-            final boolean enabled = mPlatformCompat.isChangeEnabledByPackageName(
-                    USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM);
+            final boolean enabled = Build.isDebuggable()
+                    && (enabledByDeviceConfig
+                        || mPlatformCompat.isChangeEnabledByPackageName(
+                        USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM));
             if (enabled != mEnabled) {
                 Slog.i(TAG, (enabled ? "Enabling" : "Disabling") + " component aliases...");
                 if (enabled) {
@@ -172,6 +180,7 @@
                 }
             }
             mEnabled = enabled;
+            mEnabledByDeviceConfig = enabledByDeviceConfig;
             mOverrideString = overrides;
 
             if (mEnabled) {
@@ -184,7 +193,7 @@
 
     private void refresh() {
         synchronized (mLock) {
-            update(mOverrideString);
+            update(mEnabledByDeviceConfig, mOverrideString);
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 5330845..daf3561 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -500,12 +500,11 @@
         }
     }
 
-    /*package*/ void setWiredDeviceConnectionState(int type,
-            @AudioService.ConnectionState int state, String address, String name,
-            String caller) {
+    /*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+            @AudioService.ConnectionState int state, String caller) {
         //TODO move logging here just like in setBluetooth* methods
         synchronized (mDeviceStateLock) {
-            mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+            mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);
         }
     }
 
@@ -1013,11 +1012,9 @@
         }
     }
 
-    /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
-                                                       String deviceName) {
+    /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
         synchronized (mDeviceStateLock) {
-            return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName,
-                    false /*for test*/);
+            return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 4ae1bd37..0e29041 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -230,19 +230,15 @@
      * A class just for packaging up a set of connection parameters.
      */
     /*package*/ class WiredDeviceConnectionState {
-        public final int mType;
+        public final AudioDeviceAttributes mAttributes;
         public final @AudioService.ConnectionState int mState;
-        public final String mAddress;
-        public final String mName;
         public final String mCaller;
         public boolean mForTest = false;
 
-        /*package*/ WiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
-                                               String address, String name, String caller) {
-            mType = type;
+        /*package*/ WiredDeviceConnectionState(AudioDeviceAttributes attributes,
+                @AudioService.ConnectionState int state, String caller) {
+            mAttributes = attributes;
             mState = state;
-            mAddress = address;
-            mName = name;
             mCaller = caller;
         }
     }
@@ -280,11 +276,10 @@
         synchronized (mDevicesLock) {
             //TODO iterate on mApmConnectedDevices instead once it handles all device types
             for (DeviceInfo di : mConnectedDevices.values()) {
-                mAudioSystem.setDeviceConnectionState(
-                        di.mDeviceType,
-                        AudioSystem.DEVICE_STATE_AVAILABLE,
+                mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(di.mDeviceType,
                         di.mDeviceAddress,
-                        di.mDeviceName,
+                        di.mDeviceName),
+                        AudioSystem.DEVICE_STATE_AVAILABLE,
                         di.mDeviceCodecFormat);
             }
         }
@@ -519,41 +514,45 @@
 
     /*package*/ void onSetWiredDeviceConnectionState(
                             AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
+        int type = wdcs.mAttributes.getInternalType();
+
         AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));
 
         MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
                 + "onSetWiredDeviceConnectionState")
-                .set(MediaMetrics.Property.ADDRESS, wdcs.mAddress)
-                .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(wdcs.mType))
+                .set(MediaMetrics.Property.ADDRESS, wdcs.mAttributes.getAddress())
+                .set(MediaMetrics.Property.DEVICE,
+                        AudioSystem.getDeviceName(type))
                 .set(MediaMetrics.Property.STATE,
                         wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
                                 ? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);
         synchronized (mDevicesLock) {
             if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
-                    && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
+                    && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
                 mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/,
                         "onSetWiredDeviceConnectionState state DISCONNECTED");
             }
 
-            if (!handleDeviceConnection(wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED,
-                    wdcs.mType, wdcs.mAddress, wdcs.mName, wdcs.mForTest)) {
+            if (!handleDeviceConnection(wdcs.mAttributes,
+                    wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
                 // change of connection state failed, bailout
                 mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
                         .record();
                 return;
             }
             if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
-                if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
+                if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
                     mDeviceBroker.setBluetoothA2dpOnInt(false, false /*fromA2dp*/,
                             "onSetWiredDeviceConnectionState state not DISCONNECTED");
                 }
-                mDeviceBroker.checkMusicActive(wdcs.mType, wdcs.mCaller);
+                mDeviceBroker.checkMusicActive(type, wdcs.mCaller);
             }
-            if (wdcs.mType == AudioSystem.DEVICE_OUT_HDMI) {
+            if (type == AudioSystem.DEVICE_OUT_HDMI) {
                 mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
             }
-            sendDeviceConnectionIntent(wdcs.mType, wdcs.mState, wdcs.mAddress, wdcs.mName);
-            updateAudioRoutes(wdcs.mType, wdcs.mState);
+            sendDeviceConnectionIntent(type, wdcs.mState,
+                    wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());
+            updateAudioRoutes(type, wdcs.mState);
         }
         mmi.record();
     }
@@ -572,12 +571,12 @@
                 return;
             }
             // Toggle HDMI to retrigger broadcast with proper formats.
-            setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
-                    AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
-                    "android"); // disconnect
-            setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
-                    AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
-                    "android"); // reconnect
+            setWiredDeviceConnectionState(
+                    new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+                    AudioSystem.DEVICE_STATE_UNAVAILABLE, "android"); // disconnect
+            setWiredDeviceConnectionState(
+                    new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+                    AudioSystem.DEVICE_STATE_AVAILABLE, "android"); // reconnect
         }
         mmi.record();
     }
@@ -707,16 +706,17 @@
 
     /**
      * Implements the communication with AudioSystem to (dis)connect a device in the native layers
+     * @param attributes the attributes of the device
      * @param connect true if connection
-     * @param device the device type
-     * @param address the address of the device
-     * @param deviceName human-readable name of device
      * @param isForTesting if true, not calling AudioSystem for the connection as this is
      *                    just for testing
      * @return false if an error was reported by AudioSystem
      */
-    /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
-            String deviceName, boolean isForTesting) {
+    /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
+            boolean isForTesting) {
+        int device = attributes.getInternalType();
+        String address = attributes.getAddress();
+        String deviceName = attributes.getName();
         if (AudioService.DEBUG_DEVICES) {
             Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
                     + Integer.toHexString(device) + " address:" + address
@@ -743,9 +743,8 @@
                 if (isForTesting) {
                     res = AudioSystem.AUDIO_STATUS_OK;
                 } else {
-                    res = mAudioSystem.setDeviceConnectionState(device,
-                            AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
-                            AudioSystem.AUDIO_FORMAT_DEFAULT);
+                    res = mAudioSystem.setDeviceConnectionState(attributes,
+                            AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
                 }
                 if (res != AudioSystem.AUDIO_STATUS_OK) {
                     final String reason = "not connecting device 0x" + Integer.toHexString(device)
@@ -762,9 +761,8 @@
                 mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
                 return true;
             } else if (!connect && isConnected) {
-                mAudioSystem.setDeviceConnectionState(device,
-                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
-                        AudioSystem.AUDIO_FORMAT_DEFAULT);
+                mAudioSystem.setDeviceConnectionState(attributes,
+                        AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
                 // always remove even if disconnection failed
                 mConnectedDevices.remove(deviceKey);
                 mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -941,13 +939,13 @@
         return delay;
     }
 
-    /*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
-                                                  String address, String name, String caller) {
+    /*package*/ int setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+            @AudioService.ConnectionState int state, String caller) {
         synchronized (mDevicesLock) {
-            int delay = checkSendBecomingNoisyIntentInt(type, state, AudioSystem.DEVICE_NONE);
+            int delay = checkSendBecomingNoisyIntentInt(
+                    attributes.getInternalType(), state, AudioSystem.DEVICE_NONE);
             mDeviceBroker.postSetWiredDeviceConnectionState(
-                    new WiredDeviceConnectionState(type, state, address, name, caller),
-                    delay);
+                    new WiredDeviceConnectionState(attributes, state, caller), delay);
             return delay;
         }
     }
@@ -955,8 +953,7 @@
     /*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
             @AudioService.ConnectionState int state) {
         final WiredDeviceConnectionState connection = new WiredDeviceConnectionState(
-                device.getInternalType(), state, device.getAddress(),
-                "test device", "com.android.server.audio");
+                device, state, "com.android.server.audio");
         connection.mForTest = true;
         onSetWiredDeviceConnectionState(connection);
     }
@@ -972,8 +969,9 @@
         mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
         // at this point there could be another A2DP device already connected in APM, but it
         // doesn't matter as this new one will overwrite the previous one
-        final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
+        final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
+                AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
 
         // TODO: log in MediaMetrics once distinction between connection failure and
         // double connection is made.
@@ -1035,8 +1033,9 @@
 
         // device to remove was visible by APM, update APM
         mDeviceBroker.clearAvrcpAbsoluteVolumeSupported();
-        final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "", a2dpCodec);
+        final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
 
         if (res != AudioSystem.AUDIO_STATUS_OK) {
             AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
@@ -1074,8 +1073,9 @@
 
     @GuardedBy("mDevicesLock")
     private void makeA2dpSrcAvailable(String address) {
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, "",
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                AudioSystem.DEVICE_STATE_AVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
@@ -1085,8 +1085,9 @@
 
     @GuardedBy("mDevicesLock")
     private void makeA2dpSrcUnavailable(String address) {
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
@@ -1099,8 +1100,9 @@
                 AudioSystem.DEVICE_OUT_HEARING_AID);
         mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
 
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_HEARING_AID, address, name),
+                AudioSystem.DEVICE_STATE_AVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
@@ -1122,8 +1124,9 @@
 
     @GuardedBy("mDevicesLock")
     private void makeHearingAidDeviceUnavailable(String address) {
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_HEARING_AID, address),
+                AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
@@ -1140,14 +1143,14 @@
     private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
             String eventSource) {
         if (device != AudioSystem.DEVICE_NONE) {
-
             /* Audio Policy sees Le Audio similar to A2DP. Let's make sure
              * AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
              */
             mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
 
-            AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
-                    address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
+            AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address, name),
+                    AudioSystem.DEVICE_STATE_AVAILABLE,
+                    AudioSystem.AUDIO_FORMAT_DEFAULT);
             mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
                     new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
             mDeviceBroker.postAccessoryPlugMediaUnmute(device);
@@ -1168,8 +1171,9 @@
     @GuardedBy("mDevicesLock")
     private void makeLeAudioDeviceUnavailable(String address, int device) {
         if (device != AudioSystem.DEVICE_NONE) {
-            AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                    address, "", AudioSystem.AUDIO_FORMAT_DEFAULT);
+            AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address),
+                    AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                    AudioSystem.AUDIO_FORMAT_DEFAULT);
             mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
         }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4494d96..05955c3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6371,23 +6371,23 @@
     /**
      * see AudioManager.setWiredDeviceConnectionState()
      */
-    public void setWiredDeviceConnectionState(int type,
-            @ConnectionState int state, String address, String name,
-            String caller) {
+    public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+            @ConnectionState int state, String caller) {
         enforceModifyAudioRoutingPermission();
         if (state != CONNECTION_STATE_CONNECTED
                 && state != CONNECTION_STATE_DISCONNECTED) {
             throw new IllegalArgumentException("Invalid state " + state);
         }
         new MediaMetrics.Item(mMetricsId + "setWiredDeviceConnectionState")
-                .set(MediaMetrics.Property.ADDRESS, address)
+                .set(MediaMetrics.Property.ADDRESS, attributes.getAddress())
                 .set(MediaMetrics.Property.CLIENT_NAME, caller)
-                .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(type))
-                .set(MediaMetrics.Property.NAME, name)
+                .set(MediaMetrics.Property.DEVICE,
+                        AudioSystem.getDeviceName(attributes.getInternalType()))
+                .set(MediaMetrics.Property.NAME, attributes.getName())
                 .set(MediaMetrics.Property.STATE,
                         state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")
                 .record();
-        mDeviceBroker.setWiredDeviceConnectionState(type, state, address, name, caller);
+        mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);
     }
 
     /** @see AudioManager#setTestDeviceConnectionState(AudioDeviceAttributes, boolean) */
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 3137fa5..3225274 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -116,10 +116,11 @@
         @Override
         public String eventToString() {
             return new StringBuilder("setWiredDeviceConnectionState(")
-                    .append(" type:").append(Integer.toHexString(mState.mType))
+                    .append(" type:").append(
+                            Integer.toHexString(mState.mAttributes.getInternalType()))
                     .append(" state:").append(AudioSystem.deviceStateToString(mState.mState))
-                    .append(" addr:").append(mState.mAddress)
-                    .append(" name:").append(mState.mName)
+                    .append(" addr:").append(mState.mAttributes.getAddress())
+                    .append(" name:").append(mState.mAttributes.getName())
                     .append(") from ").append(mState.mCaller).toString();
         }
     }
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index a2ba76b..f572261 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -258,19 +258,16 @@
     }
 
     /**
-     * Same as {@link AudioSystem#setDeviceConnectionState(int, int, String, String, int)}
-     * @param device
+     * Same as {@link AudioSystem#setDeviceConnectionState(AudioDeviceAttributes, int, int)}
+     * @param attributes
      * @param state
-     * @param deviceAddress
-     * @param deviceName
      * @param codecFormat
      * @return
      */
-    public int setDeviceConnectionState(int device, int state, String deviceAddress,
-                                        String deviceName, int codecFormat) {
+    public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+            int codecFormat) {
         invalidateRoutingCache();
-        return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName,
-                codecFormat);
+        return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat);
     }
 
     /**
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index a006b91..3491cd5 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -595,8 +595,9 @@
         String btDeviceName =  getName(btDevice);
         boolean result = false;
         if (isActive) {
-            result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
-                    audioDevice.getAddress(), btDeviceName);
+            result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+                    audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
+                    isActive);
         } else {
             int[] outDeviceTypes = {
                     AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -604,13 +605,15 @@
                     AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
             };
             for (int outDeviceType : outDeviceTypes) {
-                result |= mDeviceBroker.handleDeviceConnection(
-                        isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
+                result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+                        outDeviceType, audioDevice.getAddress(), btDeviceName),
+                        isActive);
             }
         }
         // handleDeviceConnection() && result to make sure the method get executed
-        result = mDeviceBroker.handleDeviceConnection(
-                isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
+        result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+                        inDevice, audioDevice.getAddress(), btDeviceName),
+                isActive) && result;
         return result;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index afcd3dd..1ce36b1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -41,7 +41,10 @@
 import android.hardware.hdmi.HdmiTimerRecordSources;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
-import android.media.AudioSystem;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioProfile;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager.TvInputCallback;
 import android.util.Slog;
@@ -58,6 +61,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Represent a logical device of type TV residing in Android system.
@@ -816,12 +820,23 @@
 
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
         boolean oldStatus = mArcEstablished;
-        // 1. Enable/disable ARC circuit.
-        enableAudioReturnChannel(enabled);
-        // 2. Notify arc status to audio service.
-        notifyArcStatusToAudioService(enabled);
-        // 3. Update arc status;
-        mArcEstablished = enabled;
+        if (enabled) {
+            RequestSadAction action = new RequestSadAction(
+                    this, Constants.ADDR_AUDIO_SYSTEM,
+                    new RequestSadAction.RequestSadCallback() {
+                        @Override
+                        public void onRequestSadDone(List<byte[]> supportedSads) {
+                            enableAudioReturnChannel(enabled);
+                            notifyArcStatusToAudioService(enabled, supportedSads);
+                            mArcEstablished = enabled;
+                        }
+                    });
+            addAndStartAction(action);
+        } else {
+            enableAudioReturnChannel(enabled);
+            notifyArcStatusToAudioService(enabled, new ArrayList<>());
+            mArcEstablished = enabled;
+        }
         return oldStatus;
     }
 
@@ -843,11 +858,15 @@
         return mService.isConnected(portId);
     }
 
-    private void notifyArcStatusToAudioService(boolean enabled) {
+    private void notifyArcStatusToAudioService(boolean enabled, List<byte[]> supportedSads) {
         // Note that we don't set any name to ARC.
-        mService.getAudioManager().setWiredDeviceConnectionState(
-                AudioSystem.DEVICE_OUT_HDMI_ARC,
-                enabled ? 1 : 0, "", "");
+        AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_ARC, "", "",
+                new ArrayList<AudioProfile>(), supportedSads.stream()
+                .map(sad -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,
+                        AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, sad))
+                .collect(Collectors.toList()));
+        mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
     }
 
     /**
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bfaa7b3..354d183 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -150,8 +150,6 @@
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
-    private static final boolean USE_SPY_WINDOW_GESTURE_MONITORS = true;
-
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
     private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
 
@@ -303,7 +301,7 @@
             int locationKeyCode);
     private static native InputChannel nativeCreateInputChannel(long ptr, String name);
     private static native InputChannel nativeCreateInputMonitor(long ptr, int displayId,
-            boolean isGestureMonitor, String name, int pid);
+            String name, int pid);
     private static native void nativeRemoveInputChannel(long ptr, IBinder connectionToken);
     private static native void nativePilferPointers(long ptr, IBinder token);
     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
@@ -720,8 +718,7 @@
             throw new IllegalArgumentException("displayId must >= 0.");
         }
 
-        return nativeCreateInputMonitor(mPtr, displayId, false /* isGestureMonitor */,
-                inputChannelName, Binder.getCallingPid());
+        return nativeCreateInputMonitor(mPtr, displayId, inputChannelName, Binder.getCallingPid());
     }
 
     @NonNull
@@ -790,10 +787,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             final InputChannel inputChannel =
-                    USE_SPY_WINDOW_GESTURE_MONITORS
-                            ? createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid)
-                            : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/,
-                                    requestedName, pid);
+                            createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid);
             return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -3375,11 +3369,7 @@
 
         @Override
         public void dispose() {
-            if (USE_SPY_WINDOW_GESTURE_MONITORS) {
-                removeSpyWindowGestureMonitor(mInputChannelToken);
-                return;
-            }
-            nativeRemoveInputChannel(mPtr, mInputChannelToken);
+            removeSpyWindowGestureMonitor(mInputChannelToken);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 9f086e6..d745a23 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -48,8 +48,8 @@
 import com.android.server.pm.dex.ArtManagerService;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SELinuxUtil;
 
 import dalvik.system.VMRuntime;
 
@@ -549,6 +549,10 @@
     }
 
     public void migrateKeyStoreData(int previousAppId, int appId) {
+        // If previous UID is system UID, declaring inheritKeyStoreKeys is not supported.
+        // Silently ignore the request to migrate keys.
+        if (previousAppId == Process.SYSTEM_UID) return;
+
         for (int userId : mPm.resolveUserIds(UserHandle.USER_ALL)) {
             int srcUid = UserHandle.getUid(userId, previousAppId);
             int destUid = UserHandle.getUid(userId, appId);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b07cd106..652080a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2515,13 +2515,17 @@
         return 0 < getRemainingCreatableProfileCount(userType, userId, allowedToRemoveOne);
     }
 
+    @Override
+    public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId) {
+        return getRemainingCreatableProfileCount(userType, userId, false);
+    }
+
     /**
      * Returns the remaining number of profiles of the given type that can be added to the given
      * user. (taking into account the total number of users on the device as well as how many
      * profiles exist of that type both in general and for the given user)
      */
-    @Override
-    public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId,
+    private int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId,
             boolean allowedToRemoveOne) {
         checkQueryOrCreateUsersPermission(
                 "get the remaining number of profiles that can be added to the given user.");
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index d455be7..46fde4b 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -108,14 +108,18 @@
      * </p>
      * @param packageName The package to start a one-time permission session for
      * @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+     * @param revokeAfterKilledDelayMillis Number of milliseconds to wait after the process dies
+     *                                     before ending the session. Set to -1 to use default value
+     *                                     for the device.
      * @param importanceToResetTimer The least important level to uid must be to reset the timer
      * @param importanceToKeepSessionAlive The least important level the uid must be to keep the
-     *                                    session alive
+     *                                     session alive
      *
      * @hide
      */
     void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis,
-            int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            long revokeAfterKilledDelayMillis, int importanceToResetTimer,
+            int importanceToKeepSessionAlive) {
         int uid;
         try {
             uid = mContext.getPackageManager().getPackageUid(packageName, 0);
@@ -126,11 +130,15 @@
 
         synchronized (mLock) {
             PackageInactivityListener listener = mListeners.get(uid);
-            if (listener == null) {
-                listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+            if (listener != null) {
+                listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis,
                         importanceToResetTimer, importanceToKeepSessionAlive);
-                mListeners.put(uid, listener);
+                return;
             }
+            listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+                    revokeAfterKilledDelayMillis, importanceToResetTimer,
+                    importanceToKeepSessionAlive);
+            mListeners.put(uid, listener);
         }
     }
 
@@ -159,18 +167,6 @@
     }
 
     /**
-     * The delay to wait before revoking on the event an app is terminated. Recommended to be long
-     * enough so that apps don't lose permission on an immediate restart
-     */
-    private long getKilledDelayMillis(boolean isSelfRevokedPermissionSession) {
-        if (isSelfRevokedPermissionSession) {
-            return 0;
-        }
-        return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
-                PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS);
-    }
-
-    /**
      * Register to listen for Uids being uninstalled. This must be done outside of the
      * PermissionManagerService lock.
      */
@@ -178,18 +174,6 @@
         mContext.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED));
     }
 
-    void setSelfRevokedPermissionSession(int uid) {
-        synchronized (mLock) {
-            PackageInactivityListener listener = mListeners.get(uid);
-            if (listener == null) {
-                Log.e(LOG_TAG, "Could not set session for uid " + uid
-                        + " as self-revoke session: session not found");
-                return;
-            }
-            listener.setSelfRevokedPermissionSession();
-        }
-    }
-
     /**
      * A class which watches a package for inactivity and notifies the permission controller when
      * the package becomes inactive
@@ -200,11 +184,11 @@
 
         private final int mUid;
         private final @NonNull String mPackageName;
-        private final long mTimeout;
-        private final int mImportanceToResetTimer;
-        private final int mImportanceToKeepSessionAlive;
+        private long mTimeout;
+        private long mRevokeAfterKilledDelay;
+        private int mImportanceToResetTimer;
+        private int mImportanceToKeepSessionAlive;
 
-        private boolean mIsSelfRevokedPermissionSession;
         private boolean mIsAlarmSet;
         private boolean mIsFinished;
 
@@ -218,16 +202,23 @@
         private final Object mToken = new Object();
 
         private PackageInactivityListener(int uid, @NonNull String packageName, long timeout,
-                int importanceToResetTimer, int importanceToKeepSessionAlive) {
+                long revokeAfterkilledDelay, int importanceToResetTimer,
+                int importanceToKeepSessionAlive) {
 
             Log.i(LOG_TAG,
                     "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout
+                            + " killedDelay=" + revokeAfterkilledDelay
                             + " importanceToResetTimer=" + importanceToResetTimer
                             + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive);
 
             mUid = uid;
             mPackageName = packageName;
             mTimeout = timeout;
+            mRevokeAfterKilledDelay = revokeAfterkilledDelay == -1
+                    ? DeviceConfig.getLong(
+                            DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY,
+                            DEFAULT_KILLED_DELAY_MILLIS)
+                    : revokeAfterkilledDelay;
             mImportanceToResetTimer = importanceToResetTimer;
             mImportanceToKeepSessionAlive = importanceToKeepSessionAlive;
 
@@ -247,6 +238,28 @@
             onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
         }
 
+        public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis,
+                int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            synchronized (mInnerLock) {
+                mTimeout = Math.min(mTimeout, timeoutMillis);
+                mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay,
+                        revokeAfterKilledDelayMillis == -1
+                                ? DeviceConfig.getLong(
+                                DeviceConfig.NAMESPACE_PERMISSIONS,
+                                PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS)
+                                : revokeAfterKilledDelayMillis);
+                mImportanceToResetTimer = Math.min(importanceToResetTimer, mImportanceToResetTimer);
+                mImportanceToKeepSessionAlive = Math.min(importanceToKeepSessionAlive,
+                        mImportanceToKeepSessionAlive);
+                Log.v(LOG_TAG,
+                        "Updated params for " + mPackageName + ". timeout=" + mTimeout
+                                + " killedDelay=" + mRevokeAfterKilledDelay
+                                + " importanceToResetTimer=" + mImportanceToResetTimer
+                                + " importanceToKeepSessionAlive=" + mImportanceToKeepSessionAlive);
+                onImportanceChanged(mUid, mActivityManager.getPackageImportance(mPackageName));
+            }
+        }
+
         private void onImportanceChanged(int uid, int importance) {
             if (uid != mUid) {
                 return;
@@ -271,7 +284,7 @@
                             }
                             onImportanceChanged(mUid, imp);
                         }
-                    }, mToken, getKilledDelayMillis(mIsSelfRevokedPermissionSession));
+                    }, mToken, mRevokeAfterKilledDelay);
                     return;
                 }
                 if (importance > mImportanceToResetTimer) {
@@ -307,14 +320,6 @@
         }
 
         /**
-         * Marks the session as a self-revoke session, which does not delay the revocation when
-         * the app is restarting.
-         */
-        public void setSelfRevokedPermissionSession() {
-            mIsSelfRevokedPermissionSession = true;
-        }
-
-        /**
          * Set the alarm which will callback when the package is inactive
          */
         @GuardedBy("mInnerLock")
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index edc0e3d..695d6dd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -68,7 +68,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.LocalServices;
@@ -388,7 +387,8 @@
 
     @Override
     public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
-            long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            long timeoutMillis, long revokeAfterKilledDelayMillis, int importanceToResetTimer,
+            int importanceToKeepSessionAlive) {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
                 "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
@@ -398,7 +398,8 @@
         final long token = Binder.clearCallingIdentity();
         try {
             getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
-                    timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+                    timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
+                    importanceToKeepSessionAlive);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -563,16 +564,7 @@
     @Override
     public void revokeOwnPermissionsOnKill(@NonNull String packageName,
             @NonNull List<String> permissions) {
-        final int callingUid = Binder.getCallingUid();
-        final int callingUserId = UserHandle.getUserId(callingUid);
-        AndroidFuture<Void> future = new AndroidFuture<>();
-        future.whenComplete((result, err) -> {
-            if (err == null) {
-                getOneTimePermissionUserManager(callingUserId)
-                        .setSelfRevokedPermissionSession(callingUid);
-            }
-        });
-        mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions, future);
+        mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
     }
 
     @Override
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 db9c1b5..ed351fd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -108,7 +108,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.compat.IPlatformCompat;
-import com.android.internal.infra.AndroidFuture;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.os.RoSystemProperties;
@@ -1592,8 +1591,7 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
-            AndroidFuture<Void> callback) {
+    public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
         final int callingUid = Binder.getCallingUid();
         int callingUserId = UserHandle.getUserId(callingUid);
         int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
@@ -1608,8 +1606,7 @@
                         + permName + " because it does not hold that permission");
             }
         }
-        mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions,
-                callback);
+        mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
     }
 
     private boolean mayManageRolePermission(int uid) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 91c558b..3e28320 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -27,7 +27,6 @@
 import android.permission.IOnPermissionsChangeListener;
 import android.permission.PermissionManagerInternal;
 
-import com.android.internal.infra.AndroidFuture;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
@@ -338,16 +337,16 @@
      * <li>Each permission in {@code permissions} must be a runtime permission.
      * </ul>
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. This revocation happens asynchronously and kills all processes running in the
-     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * This revocation happens asynchronously and kills all processes running in the same UID as
+     * {@code packageName}. It will be triggered once it is safe to do so.
      *
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
-     * @param callback Callback called when the revocation request has been completed.
      */
-    void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
-            AndroidFuture<Void> callback);
+    void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
 
     /**
      * Get whether you should show UI with rationale for requesting a permission. You should do this
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d4ae90..ca4d717 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -24,6 +24,7 @@
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
+import static android.Manifest.permission.MANAGE_GAME_ACTIVITY;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REMOVE_TASKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
@@ -1771,6 +1772,43 @@
     }
 
     @Override
+    public int startActivityFromGameSession(IApplicationThread caller, String callingPackage,
+            String callingFeatureId, int callingPid, int callingUid, Intent intent, int taskId,
+            int userId) {
+        if (checkCallingPermission(MANAGE_GAME_ACTIVITY) != PERMISSION_GRANTED) {
+            final String msg = "Permission Denial: startActivityFromGameSession() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + MANAGE_GAME_ACTIVITY;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        assertPackageMatchesCallingUid(callingPackage);
+
+        final ActivityOptions activityOptions = ActivityOptions.makeBasic();
+        activityOptions.setLaunchTaskId(taskId);
+
+        userId = handleIncomingUser(callingPid, callingUid, userId, "startActivityFromGameSession");
+
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            return getActivityStartController()
+                    .obtainStarter(intent, "startActivityFromGameSession")
+                    .setCaller(caller)
+                    .setCallingUid(callingUid)
+                    .setCallingPid(callingPid)
+                    .setCallingPackage(intent.getPackage())
+                    .setCallingFeatureId(callingFeatureId)
+                    .setUserId(userId)
+                    .setActivityOptions(activityOptions.toBundle())
+                    .setRealCallingUid(Binder.getCallingUid())
+                    .execute();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public BackNavigationInfo startBackNavigation() {
         mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
                 "startBackNavigation()");
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8cb27e1..e5529f1 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -265,7 +265,6 @@
     base::Result<std::unique_ptr<InputChannel>> createInputChannel(JNIEnv* env,
                                                                    const std::string& name);
     base::Result<std::unique_ptr<InputChannel>> createInputMonitor(JNIEnv* env, int32_t displayId,
-                                                                   bool isGestureMonitor,
                                                                    const std::string& name,
                                                                    int32_t pid);
     status_t removeInputChannel(JNIEnv* env, const sp<IBinder>& connectionToken);
@@ -522,11 +521,9 @@
 }
 
 base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
-        JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name,
-        int32_t pid) {
+        JNIEnv* /* env */, int32_t displayId, const std::string& name, int32_t pid) {
     ATRACE_CALL();
-    return mInputManager->getDispatcher().createInputMonitor(displayId, isGestureMonitor, name,
-                                                             pid);
+    return mInputManager->getDispatcher().createInputMonitor(displayId, name, pid);
 }
 
 status_t NativeInputManager::removeInputChannel(JNIEnv* /* env */,
@@ -1659,7 +1656,7 @@
 }
 
 static jobject nativeCreateInputMonitor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId,
-                                        jboolean isGestureMonitor, jstring nameObj, jint pid) {
+                                        jstring nameObj, jint pid) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     if (displayId == ADISPLAY_ID_NONE) {
@@ -1672,7 +1669,7 @@
     std::string name = nameChars.c_str();
 
     base::Result<std::unique_ptr<InputChannel>> inputChannel =
-            im->createInputMonitor(env, displayId, isGestureMonitor, name, pid);
+            im->createInputMonitor(env, displayId, name, pid);
 
     if (!inputChannel.ok()) {
         std::string message = inputChannel.error().message();
@@ -2381,7 +2378,7 @@
         {"nativeGetKeyCodeForKeyLocation", "(JII)I", (void*)nativeGetKeyCodeForKeyLocation},
         {"nativeCreateInputChannel", "(JLjava/lang/String;)Landroid/view/InputChannel;",
          (void*)nativeCreateInputChannel},
-        {"nativeCreateInputMonitor", "(JIZLjava/lang/String;I)Landroid/view/InputChannel;",
+        {"nativeCreateInputMonitor", "(JILjava/lang/String;I)Landroid/view/InputChannel;",
          (void*)nativeCreateInputMonitor},
         {"nativeRemoveInputChannel", "(JLandroid/os/IBinder;)V", (void*)nativeRemoveInputChannel},
         {"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e99b1f9..8465770 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -134,6 +134,7 @@
 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;
+import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.provider.Telephony.Carriers.DPC_URI;
 import static android.provider.Telephony.Carriers.ENFORCE_KEY;
@@ -222,6 +223,7 @@
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -11613,6 +11615,7 @@
 
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+                || isFinancedDeviceOwner(caller)
                 || isProfileOwner(caller)
                 || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
 
@@ -13988,7 +13991,7 @@
 
         synchronized (getLockObject()) {
             if (isFinancedDeviceOwner(caller)) {
-                enforceCanSetPermissionGrantOnFinancedDevice(packageName, permission);
+                enforcePermissionGrantStateOnFinancedDevice(packageName, permission);
             }
             long ident = mInjector.binderClearCallingIdentity();
             try {
@@ -14049,14 +14052,14 @@
         }
     }
 
-    private void enforceCanSetPermissionGrantOnFinancedDevice(
+    private void enforcePermissionGrantStateOnFinancedDevice(
             String packageName, String permission) {
         if (!Manifest.permission.READ_PHONE_STATE.equals(permission)) {
-            throw new SecurityException("Cannot grant " + permission
-                    + " when managing a financed device");
+            throw new SecurityException(permission + " cannot be used when managing a financed"
+                    + " device for permission grant state");
         } else if (!mOwners.getDeviceOwnerPackageName().equals(packageName)) {
-            throw new SecurityException("Cannot grant permission to a package that is not"
-                    + " the device owner");
+            throw new SecurityException("Device owner package is the only package that can be used"
+                    + " for permission grant state when managing a financed device");
         }
     }
 
@@ -14065,10 +14068,14 @@
             String packageName, String permission) throws RemoteException {
         final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
         Preconditions.checkCallAuthorization(isSystemUid(caller) || (caller.hasAdminComponent()
-                && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+                && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+                || isFinancedDeviceOwner(caller)))
                 || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
 
         synchronized (getLockObject()) {
+            if (isFinancedDeviceOwner(caller)) {
+                enforcePermissionGrantStateOnFinancedDevice(packageName, permission);
+            }
             return mInjector.binderWithCleanCallingIdentity(() -> {
                 int granted;
                 if (getTargetSdk(caller.getPackageName(), caller.getUserId())
@@ -18669,4 +18676,26 @@
             mContext.sendBroadcastAsUser(intent, user);
         }
     }
+
+    public boolean isDpcDownloaded() {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+        ContentResolver cr = mContext.getContentResolver();
+
+        return mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.getIntForUser(
+                cr, MANAGED_PROVISIONING_DPC_DOWNLOADED,
+                /* def= */ 0, /* userHandle= */ cr.getUserId())
+                == 1);
+    }
+
+    public void setDpcDownloaded(boolean downloaded) {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+        int setTo = downloaded ? 1 : 0;
+
+        mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
+                mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c2dec06..a111831 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -3171,11 +3171,6 @@
     }
 
     private void startAmbientContextService(@NonNull TimingsTraceAndSlog t) {
-        if (!AmbientContextManagerService.isDetectionServiceConfigured()) {
-            Slog.d(TAG, "AmbientContextDetectionService is not configured on this device");
-            return;
-        }
-
         t.traceBegin("StartAmbientContextService");
         mSystemServiceManager.startService(AmbientContextManagerService.class);
         t.traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index bdea679..dad9fe8 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -28,6 +28,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.content.Intent;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.BluetoothProfileConnectionInfo;
@@ -186,8 +187,9 @@
         doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup(
                 any(Intent.class));
 
-        mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
-                AudioService.CONNECTION_STATE_CONNECTED, address, name, caller);
+        mSpyDevInventory.setWiredDeviceConnectionState(new AudioDeviceAttributes(
+                        AudioSystem.DEVICE_OUT_WIRED_HEADSET, address, name),
+                AudioService.CONNECTION_STATE_CONNECTED, caller);
         Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
 
         // Verify that the sticky intent is broadcasted
@@ -246,11 +248,11 @@
      */
     private void checkSingleSystemConnection(BluetoothDevice btDevice) throws Exception {
         final String expectedName = btDevice.getName() == null ? "" : btDevice.getName();
+        AudioDeviceAttributes expected = new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, btDevice.getAddress(), expectedName);
         verify(mSpyAudioSystem, times(1)).setDeviceConnectionState(
-                ArgumentMatchers.eq(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+                ArgumentMatchers.argThat(x -> x.equalTypeAddress(expected)),
                 ArgumentMatchers.eq(AudioSystem.DEVICE_STATE_AVAILABLE),
-                ArgumentMatchers.eq(btDevice.getAddress()),
-                ArgumentMatchers.eq(expectedName),
                 anyInt() /*codec*/);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 8d706cb..1f355b0 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -48,11 +48,10 @@
     //-----------------------------------------------------------------
     // Overrides of AudioSystemAdapter
     @Override
-    public int setDeviceConnectionState(int device, int state, String deviceAddress,
-            String deviceName, int codecFormat) {
-        Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, %s, %s, 0x%s",
-                Integer.toHexString(device), state, deviceAddress, deviceName,
-                Integer.toHexString(codecFormat)));
+    public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+            int codecFormat) {
+        Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s",
+                attributes.toString(), state, Integer.toHexString(codecFormat)));
         return AudioSystem.AUDIO_STATUS_OK;
     }
 
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 c877bd1..e7bf293 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -120,6 +120,7 @@
 import android.hardware.usb.UsbManager;
 import android.net.ProfileNetworkPreference;
 import android.net.Uri;
+import android.net.wifi.WifiSsid;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -164,6 +165,7 @@
 import java.io.File;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -7779,6 +7781,7 @@
 
                 verify(getServices().userManagerInternal, never())
                         .setDevicePolicyUserRestrictions(anyInt(), any(), any(), anyBoolean());
+                DpmTestUtils.assertRestrictions(new Bundle(), dpm.getUserRestrictions(admin1));
             }
         }
     }
@@ -7810,6 +7813,9 @@
                                 eq(true));
                 reset(getServices().userManagerInternal);
 
+                DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(restriction),
+                        dpm.getUserRestrictions(admin1));
+
                 dpm.clearUserRestriction(admin1, restriction);
                 reset(getServices().userManagerInternal);
             }
@@ -8056,6 +8062,28 @@
     }
 
     @Test
+    public void testGetPermissionGrantState_financeDo_notReadPhoneStatePermission_throwsException()
+            throws Exception {
+        setDeviceOwner();
+        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+        assertExpectException(SecurityException.class, /* messageRegex= */ null,
+                () -> dpm.getPermissionGrantState(admin1, admin1.getPackageName(),
+                        permission.READ_CALENDAR));
+    }
+
+    @Test
+    public void testGetPermissionGrantState_financeDo_notDeviceOwnerPackage_throwsException()
+            throws Exception {
+        setDeviceOwner();
+        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+        assertExpectException(SecurityException.class, /* messageRegex= */ null,
+                () -> dpm.getPermissionGrantState(admin1, "com.android.foo.package",
+                        permission.READ_PHONE_STATE));
+    }
+
+    @Test
     public void testSetUsbDataSignalingEnabled_noDeviceOwnerOrPoOfOrgOwnedDevice() {
         assertThrows(SecurityException.class,
                 () -> dpm.setUsbDataSignalingEnabled(true));
@@ -8334,7 +8362,8 @@
 
     @Test
     public void testSetSsidAllowlist_noDeviceOwnerOrPoOfOrgOwnedDevice() {
-        final Set<String> ssids = Collections.singleton("ssid1");
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
         WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids);
         assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy));
     }
@@ -8343,7 +8372,8 @@
     public void testSetSsidAllowlist_asDeviceOwner() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = Collections.singleton("ssid1");
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
         WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
@@ -8359,7 +8389,10 @@
         configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
         mContext.binder.callingUid = managedProfileAdminUid;
 
-        final Set<String> ssids = new ArraySet<>(Arrays.asList("ssid1", "ssid2", "ssid3"));
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8))));
         WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
@@ -8371,14 +8404,15 @@
     public void testSetSsidAllowlist_emptyList() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = new ArraySet<>();
+        final Set<WifiSsid> ssids = new ArraySet<>();
         assertThrows(IllegalArgumentException.class,
                 () -> WifiSsidPolicy.createAllowlistPolicy(ssids));
     }
 
     @Test
     public void testSetSsidDenylist_noDeviceOwnerOrPoOfOrgOwnedDevice() {
-        final Set<String> ssids = Collections.singleton("ssid1");
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
         WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids);
         assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy));
     }
@@ -8387,7 +8421,8 @@
     public void testSetSsidDenylist_asDeviceOwner() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = Collections.singleton("ssid1");
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
         WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
@@ -8403,7 +8438,10 @@
         configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
         mContext.binder.callingUid = managedProfileAdminUid;
 
-        final Set<String> ssids = new ArraySet<>(Arrays.asList("ssid1", "ssid2", "ssid3"));
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8))));
         WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
@@ -8415,7 +8453,7 @@
     public void testSetSsidDenylist_emptyList() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = new ArraySet<>();
+        final Set<WifiSsid> ssids = new ArraySet<>();
         assertThrows(IllegalArgumentException.class,
                 () -> WifiSsidPolicy.createDenylistPolicy(ssids));
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index b6c4bc2..a9812ab 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -62,6 +62,23 @@
 public class HdmiCecLocalDeviceTvTest {
     private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
 
+    private static final String[] SADS_NOT_TO_QUERY = new String[]{
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX};
+    private static final HdmiCecMessage SAD_QUERY =
+            HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(ADDR_TV, ADDR_AUDIO_SYSTEM,
+                    new int[]{Constants.AUDIO_CODEC_LPCM, Constants.AUDIO_CODEC_DD,
+                            Constants.AUDIO_CODEC_MP3, Constants.AUDIO_CODEC_MPEG2});
+
     private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
@@ -136,6 +153,10 @@
         mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress);
         mTestLooper.dispatchAll();
         mTvLogicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress();
+        for (String sad : SADS_NOT_TO_QUERY) {
+            mHdmiControlService.getHdmiCecConfig().setIntValue(
+                    sad, HdmiControlManager.QUERY_SAD_DISABLED);
+        }
         mNativeWrapper.clearResultMessages();
     }
 
@@ -442,6 +463,7 @@
                 ADDR_TV,
                 ADDR_AUDIO_SYSTEM);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
     }
 
     @Test
@@ -463,6 +485,7 @@
                 ADDR_TV,
                 ADDR_AUDIO_SYSTEM);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
     }
 
     @Test
@@ -485,6 +508,7 @@
                 ADDR_TV,
                 ADDR_AUDIO_SYSTEM);
         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
+        assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
     }
 
     @Test
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 85b1de5..337e1f9 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -17,6 +17,7 @@
 package com.android.server.usb;
 
 import android.annotation.NonNull;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.os.RemoteException;
@@ -213,24 +214,25 @@
                 int outputState = (enable && connected) ? 1 : 0;
                 if (outputState != mOutputState) {
                     mOutputState = outputState;
-                    mAudioService.setWiredDeviceConnectionState(device, outputState,
-                                                                alsaCardDeviceString,
-                                                                mDeviceName, TAG);
+                    AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
+                            alsaCardDeviceString, mDeviceName);
+                    mAudioService.setWiredDeviceConnectionState(attributes, outputState, TAG);
                 }
             }
 
             // Input Device
             if (mHasInput) {
-                int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
+                int device = mIsInputHeadset
+                        ? AudioSystem.DEVICE_IN_USB_HEADSET
                         : AudioSystem.DEVICE_IN_USB_DEVICE;
                 boolean connected = isInputJackConnected();
                 Slog.i(TAG, "INPUT JACK connected: " + connected);
                 int inputState = (enable && connected) ? 1 : 0;
                 if (inputState != mInputState) {
                     mInputState = inputState;
-                    mAudioService.setWiredDeviceConnectionState(
-                            device, inputState, alsaCardDeviceString,
-                            mDeviceName, TAG);
+                    AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
+                            alsaCardDeviceString, mDeviceName);
+                    mAudioService.setWiredDeviceConnectionState(attributes, inputState, TAG);
                 }
             }
         } catch (RemoteException e) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e560f34..d7cdb50 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -356,13 +356,17 @@
             "android.telecom.extra.INCOMING_CALL_EXTRAS";
 
     /**
-     * Optional extra for {@link #ACTION_INCOMING_CALL} containing a boolean to indicate that the
-     * call has an externally generated ringer. Used by the HfpClientConnectionService when In Band
-     * Ringtone is enabled to prevent two ringers from being generated.
+     * Optional extra for {@link #addNewIncomingCall(PhoneAccountHandle, Bundle)} used to indicate
+     * that a call has an in-band ringtone associated with it.  This is used when the device is
+     * acting as an HFP headset and the Bluetooth stack has received an in-band ringtone from the
+     * the HFP host which must be played instead of any local ringtone the device would otherwise
+     * have generated.
+     *
      * @hide
      */
-    public static final String EXTRA_CALL_EXTERNAL_RINGER =
-            "android.telecom.extra.CALL_EXTERNAL_RINGER";
+    @SystemApi
+    public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE =
+            "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
 
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} and
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 4978692..82333a4 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -46,16 +46,17 @@
     private final int keyType;
     //Date-Time in UTC when the key will expire.
     private final Date expirationTime;
+    private final int carrierId;
 
     /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
-                              byte[] key, Date expirationTime) {
-        this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime);
+            byte[] key, Date expirationTime, int carrierId) {
+        this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime, carrierId);
     }
 
     /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
-                              PublicKey publicKey, Date expirationTime) {
+            PublicKey publicKey, Date expirationTime, int carrierId) {
         // todo need to validate that ImsiEncryptionInfo is being created with the correct params.
         //      Including validating that the public key is in "X.509" format. This will be done in
         //      a subsequent CL.
@@ -65,6 +66,7 @@
         this.publicKey = publicKey;
         this.keyIdentifier = keyIdentifier;
         this.expirationTime = expirationTime;
+        this.carrierId = carrierId;
     }
 
     /** @hide */
@@ -78,6 +80,7 @@
         keyIdentifier = in.readString();
         keyType = in.readInt();
         expirationTime = new Date(in.readLong());
+        carrierId = in.readInt();
     }
 
     /** @hide */
@@ -90,6 +93,11 @@
         return this.mcc;
     }
 
+    /** @hide */
+    public int getCarrierId() {
+        return carrierId;
+    }
+
     /**
      * Returns key identifier, a string that helps the authentication server to locate the
      * private key to decrypt the permanent identity, or {@code null} when uavailable.
@@ -157,6 +165,7 @@
         dest.writeString(keyIdentifier);
         dest.writeInt(keyType);
         dest.writeLong(expirationTime.getTime());
+        dest.writeInt(carrierId);
     }
 
     @Override
@@ -164,10 +173,11 @@
         return "[ImsiEncryptionInfo "
                 + "mcc=" + mcc
                 + " mnc=" + mnc
-                + " publicKey=" + publicKey
+                + ", publicKey=" + publicKey
                 + ", keyIdentifier=" + keyIdentifier
                 + ", keyType=" + keyType
                 + ", expirationTime=" + expirationTime
+                + ", carrier_id=" + carrierId
                 + "]";
     }
 }
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 5a12865..e0145e6 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -79,7 +79,7 @@
     public static final int ENCODING_8BIT = 2;
     public static final int ENCODING_16BIT = 3;
     /**
-     * @hide This value is not defined in global standard. Only in Korea, this is used.
+     * This value is not defined in global standard. Only in Korea, this is used.
      */
     public static final int ENCODING_KSC5601 = 4;
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index baccb26..ba1a6ed 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9199,7 +9199,8 @@
      * @param allowedNetworkTypes The bitmask of allowed network types.
      * @return true on success; false on any failure.
      * @hide
-     * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead.
+     * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead with reason
+     * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -9233,10 +9234,7 @@
 
     /**
      * To indicate allowed network type change is requested by user.
-     *
-     * @hide
      */
-    @SystemApi
     public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0;
 
     /**
@@ -9255,10 +9253,7 @@
      * Carrier configuration won't affect the settings configured through
      * other reasons and will result in allowing network types that are in both
      * configurations (i.e intersection of both sets).
-     *
-     * @hide
      */
-    @SystemApi
     public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2;
 
     /**
@@ -9272,35 +9267,23 @@
     /**
      * Set the allowed network types of the device and provide the reason triggering the allowed
      * network change.
+     * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE or
+     * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * This can be called for following reasons
      * <ol>
      * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER}
-     * <li>Allowed network types control by power manager
-     * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER}
      * <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}
-     * <li>Allowed network types control by the user-controlled "Allow 2G" toggle
-     * {@link #ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}
      * </ol>
      * This API will result in allowing an intersection of allowed network types for all reasons,
      * including the configuration done through other reasons.
      *
-     * The functionality of this API with the parameter
-     * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API
-     * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of
-     * {@link TelephonyManager#setAllowedNetworkTypes}.
-     * <p>
-     * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
-     * ({@link TelephonyManager#CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK}) returns true, then
-     * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
-     * setPreferredNetworkTypesBitmap is used instead.
-     *
      * @param reason the reason the allowed network type change is taking place
-     * @param allowedNetworkTypes The bitmask of allowed network types.
+     * @param allowedNetworkTypes The bitmask of allowed network type
      * @throws IllegalStateException if the Telephony process is not currently available.
      * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
-     * @hide
+     * @throws SecurityException if the caller does not have the required privileges
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @RequiresFeature(
             enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
@@ -9330,18 +9313,19 @@
      *
      * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
      * specific reason.
+     * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or
+     * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param reason the reason the allowed network type change is taking place
      * @return the allowed network type bitmask
      * @throws IllegalStateException    if the Telephony process is not currently available.
      * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
-     * @hide
+     * @throws SecurityException if the caller does not have the required permission/privileges
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @RequiresFeature(
             enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
             value = TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK)
-    @SystemApi
     public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
             @AllowedNetworkTypesReason int reason) {
         if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -13560,127 +13544,88 @@
     // 2G
     /**
      * network type bitmask unknown.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L;
     /**
      * network type bitmask indicating the support of radio tech GSM.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_GSM = (1 << (NETWORK_TYPE_GSM -1));
     /**
      * network type bitmask indicating the support of radio tech GPRS.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_GPRS = (1 << (NETWORK_TYPE_GPRS -1));
     /**
      * network type bitmask indicating the support of radio tech EDGE.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EDGE = (1 << (NETWORK_TYPE_EDGE -1));
     /**
      * network type bitmask indicating the support of radio tech CDMA(IS95A/IS95B).
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_CDMA = (1 << (NETWORK_TYPE_CDMA -1));
     /**
      * network type bitmask indicating the support of radio tech 1xRTT.
-     * @hide
      */
-    @SystemApi
+    @SuppressLint("AllUpper")
     public static final long NETWORK_TYPE_BITMASK_1xRTT = (1 << (NETWORK_TYPE_1xRTT - 1));
     // 3G
     /**
      * network type bitmask indicating the support of radio tech EVDO 0.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EVDO_0 = (1 << (NETWORK_TYPE_EVDO_0 -1));
     /**
      * network type bitmask indicating the support of radio tech EVDO A.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EVDO_A = (1 << (NETWORK_TYPE_EVDO_A - 1));
     /**
      * network type bitmask indicating the support of radio tech EVDO B.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EVDO_B = (1 << (NETWORK_TYPE_EVDO_B -1));
     /**
      * network type bitmask indicating the support of radio tech EHRPD.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EHRPD = (1 << (NETWORK_TYPE_EHRPD -1));
     /**
      * network type bitmask indicating the support of radio tech HSUPA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSUPA = (1 << (NETWORK_TYPE_HSUPA -1));
     /**
      * network type bitmask indicating the support of radio tech HSDPA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSDPA = (1 << (NETWORK_TYPE_HSDPA -1));
     /**
      * network type bitmask indicating the support of radio tech HSPA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSPA = (1 << (NETWORK_TYPE_HSPA -1));
     /**
      * network type bitmask indicating the support of radio tech HSPAP.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSPAP = (1 << (NETWORK_TYPE_HSPAP -1));
     /**
      * network type bitmask indicating the support of radio tech UMTS.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_UMTS = (1 << (NETWORK_TYPE_UMTS -1));
     /**
      * network type bitmask indicating the support of radio tech TD_SCDMA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = (1 << (NETWORK_TYPE_TD_SCDMA -1));
     // 4G
     /**
      * network type bitmask indicating the support of radio tech LTE.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1));
     /**
      * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation).
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1));
 
     /**
      * network type bitmask indicating the support of radio tech NR(New Radio) 5G.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_NR = (1 << (NETWORK_TYPE_NR -1));
 
     /**
      * network type bitmask indicating the support of radio tech IWLAN.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_IWLAN = (1 << (NETWORK_TYPE_IWLAN -1));
 
     /** @hide */
@@ -13735,12 +13680,11 @@
     /**
      * @return Modem supported radio access family bitmask
      *
-     * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+     * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or
      * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
-     * @hide
+     *
+     * @throws SecurityException if the caller does not have the required permission
      */
-    @SystemApi
-    @TestApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NetworkTypeBitMask long getSupportedRadioAccessFamily() {
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 1ff6ec1..ec73471 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -261,9 +261,10 @@
     }
 
     /**
-     * Unthrottles the APN on the current transport.  There is no matching "APN throttle" method.
-     * Instead, the APN is throttled when {@link IDataService#setupDataCall} fails within
-     * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+     * Unthrottles the APN on the current transport.
+     * The APN is throttled when {@link IDataService#setupDataCall} fails within
+     * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain
+     * throttled until this method is called.
      * <p/>
      * see: {@link DataCallResponse#getRetryDurationMillis}
      *
@@ -284,9 +285,9 @@
 
     /**
      * Unthrottles the DataProfile on the current transport.
-     * There is no matching "DataProfile throttle" method.
-     * Instead, the DataProfile is throttled when {@link IDataService#setupDataCall} fails within
-     * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+     * The DataProfile is throttled when {@link IDataService#setupDataCall} fails within
+     * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain
+     * throttled until this method is called.
      * <p/>
      * see: {@link DataCallResponse#getRetryDurationMillis}
      *
diff --git a/tests/componentalias/AndroidTest-template.xml b/tests/componentalias/AndroidTest-template.xml
index 2d46217..afdfe79 100644
--- a/tests/componentalias/AndroidTest-template.xml
+++ b/tests/componentalias/AndroidTest-template.xml
@@ -21,8 +21,6 @@
         <option name="test-file-name" value="ComponentAliasTests2.apk" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android" />
-
         <!-- Exempt the helper APKs from the BG restriction, so they can start BG services. -->
         <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests" />
         <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub1" />
diff --git a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
index 89db2f7..9658d6f 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
@@ -17,6 +17,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Build;
 import android.provider.DeviceConfig;
 import android.util.Log;
 
@@ -27,6 +28,7 @@
 import com.android.compatibility.common.util.TestUtils;
 
 import org.junit.AfterClass;
+import org.junit.Assume;
 import org.junit.Before;
 
 import java.util.function.Consumer;
@@ -37,7 +39,11 @@
     protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
             DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
     @Before
-    public void enableComponentAlias() throws Exception {
+    public void enableComponentAliasWithCompatFlag() throws Exception {
+        Assume.assumeTrue(Build.isDebuggable());
+        ShellUtils.runShellCommand(
+                "am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
+        sDeviceConfig.set("enable_experimental_component_alias", "");
         sDeviceConfig.set("component_alias_overrides", "");
 
         // Make sure the feature is actually enabled.
@@ -49,6 +55,8 @@
 
     @AfterClass
     public static void restoreDeviceConfig() throws Exception {
+        ShellUtils.runShellCommand(
+                "am compat disable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
         sDeviceConfig.close();
     }
 
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
new file mode 100644
index 0000000..52c6d5b
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.content.componentalias.tests;
+
+import android.os.Build;
+import android.provider.DeviceConfig;
+
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class ComponentAliasEnableWithDeviceConfigTest {
+    protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+
+    @AfterClass
+    public static void restoreDeviceConfig() throws Exception {
+        sDeviceConfig.close();
+    }
+
+    @Test
+    public void enableComponentAliasWithCompatFlag() throws Exception {
+        Assume.assumeTrue(Build.isDebuggable());
+
+        sDeviceConfig.set("component_alias_overrides", "");
+
+        // First, disable with both compat-id and device config.
+        ShellUtils.runShellCommand(
+                "am compat disable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
+        sDeviceConfig.set("enable_experimental_component_alias", "");
+
+        TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+            return ShellUtils.runShellCommand("dumpsys activity component-alias")
+                    .indexOf("Enabled: false") > 0;
+        });
+
+        // Then, enable by device config.
+        sDeviceConfig.set("enable_experimental_component_alias", "true");
+
+        // Make sure the feature is actually enabled.
+        TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+            return ShellUtils.runShellCommand("dumpsys activity component-alias")
+                    .indexOf("Enabled: true") > 0;
+        });
+    }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
new file mode 100644
index 0000000..7935476
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.content.componentalias.tests;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+import android.provider.DeviceConfig;
+
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ShellUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Test;
+
+/**
+ * Test to make sure component-alias can't be enabled on user builds.
+ */
+public class ComponentAliasNotSupportedOnUserBuildTest {
+    protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+
+    @AfterClass
+    public static void restoreDeviceConfig() throws Exception {
+        sDeviceConfig.close();
+    }
+
+    @Test
+    public void enableComponentAliasWithCompatFlag() throws Exception {
+        Assume.assumeFalse(Build.isDebuggable());
+
+        // Try to enable it by both the device config and compat-id.
+        sDeviceConfig.set("enable_experimental_component_alias", "true");
+        ShellUtils.runShellCommand(
+                "am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
+
+        // Sleep for an arbitrary amount of time, so the config would sink in, if there was
+        // no "not on user builds" check.
+
+        Thread.sleep(5000);
+
+        // Make sure the feature is still disabled.
+        assertThat(ShellUtils.runShellCommand("dumpsys activity component-alias")
+                .indexOf("Enabled: false") > 0).isTrue();
+    }
+}