Merge "Fix ownership for ComponentOptions" into main
diff --git a/BAL_OWNERS b/BAL_OWNERS
index d56a1d4..ec779e7 100644
--- a/BAL_OWNERS
+++ b/BAL_OWNERS
@@ -2,4 +2,6 @@
 achim@google.com
 topjohnwu@google.com
 lus@google.com
+haok@google.com
+wnan@google.com
 
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index bf67187..0a3ae4f 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -16,9 +16,9 @@
 
 package android.platform.coverage
 
+import com.android.tools.metalava.model.CallableItem
 import com.android.tools.metalava.model.ClassItem
 import com.android.tools.metalava.model.Item
-import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.text.ApiFile
 import java.io.File
 import java.io.FileWriter
@@ -40,24 +40,24 @@
 
 fun extractFlaggedApisFromClass(
     classItem: ClassItem,
-    methods: List<MethodItem>,
+    callables: List<CallableItem>,
     packageName: String,
     builder: FlagApiMap.Builder
 ) {
-    if (methods.isEmpty()) return
+    if (callables.isEmpty()) return
     val classFlag = getClassFlag(classItem)
-    for (method in methods) {
-        val methodFlag = getFlagAnnotation(method) ?: classFlag
+    for (callable in callables) {
+        val callableFlag = getFlagAnnotation(callable) ?: classFlag
         val api =
             JavaMethod.newBuilder()
                 .setPackageName(packageName)
                 .setClassName(classItem.fullName())
-                .setMethodName(method.name())
-        for (param in method.parameters()) {
+                .setMethodName(callable.name())
+        for (param in callable.parameters()) {
             api.addParameters(param.type().toTypeString())
         }
-        if (methodFlag != null) {
-            addFlaggedApi(builder, api, methodFlag)
+        if (callableFlag != null) {
+            addFlaggedApi(builder, api, callableFlag)
         }
     }
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 7eb9d0f..fdf9abc4 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -236,7 +236,7 @@
         ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms",
                 mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
         preloadAnimation();
-        ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms",
+        ALOGD("%sAnimationPreloadTiming stop time: %" PRId64 "ms",
                 mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
     }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ee82b3f..76e761d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3678,7 +3678,9 @@
      * @see View#findViewById(int)
      * @see Activity#requireViewById(int)
      */
-    /* TODO(b/347672184): Re-add @Nullable */
+    // Strictly speaking this should be marked as @Nullable but the nullability of the return value
+    // is deliberately left unspecified as idiomatically correct code can make assumptions either
+    // way based on local context, e.g. layout specification.
     public <T extends View> T findViewById(@IdRes int id) {
         return getWindow().findViewById(id);
     }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 160d00c..d73d536 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -565,7 +565,9 @@
      * @see View#findViewById(int)
      * @see Dialog#requireViewById(int)
      */
-    /* TODO(b/347672184): Re-add @Nullable */
+    // Strictly speaking this should be marked as @Nullable but the nullability of the return value
+    // is deliberately left unspecified as idiomatically correct code can make assumptions either
+    // way based on local context, e.g. layout specification.
     public <T extends View> T findViewById(@IdRes int id) {
         return mWindow.findViewById(id);
     }
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 327ebd0..c9c2dcc 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -536,7 +536,9 @@
      * @see View#findViewById(int)
      * @see DreamService#requireViewById(int)
      */
-    /* TODO(b/347672184): Re-add @Nullable */
+    // Strictly speaking this should be marked as @Nullable but the nullability of the return value
+    // is deliberately left unspecified as idiomatically correct code can make assumptions either
+    // way based on local context, e.g. layout specification.
     public <T extends View> T findViewById(@IdRes int id) {
         return getWindow().findViewById(id);
     }
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index 16d6082..17adb32 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -288,6 +288,9 @@
             case R.attr.state_activated:
                 sb.append("A ");
                 break;
+            case R.attr.state_hovered:
+                sb.append("H ");
+                break;
             }
         }
 
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 9099f98..7eb6f2e 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -284,7 +284,7 @@
         if (bitmap == null) {
             throw new IllegalArgumentException("bitmap must not be null");
         }
-        validateHotSpot(bitmap, hotSpotX, hotSpotY);
+        validateHotSpot(bitmap, hotSpotX, hotSpotY, false /* isScaled */);
 
         PointerIcon icon = new PointerIcon(TYPE_CUSTOM);
         icon.mBitmap = bitmap;
@@ -517,7 +517,9 @@
 
         BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
         final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
-        validateHotSpot(bitmap, hotSpotX, hotSpotY);
+        // The bitmap and hotspot are loaded from the context, which means it is implicitly scaled
+        // to the current display density, so treat this as a scaled icon when verifying hotspot.
+        validateHotSpot(bitmap, hotSpotX, hotSpotY, true /* isScaled */);
         // Set the properties now that we have successfully loaded the icon.
         mBitmap = bitmap;
         mHotSpotX = hotSpotX;
@@ -531,11 +533,16 @@
                 + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY + "}";
     }
 
-    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) {
-        if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) {
+    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY,
+            boolean isScaled) {
+        // Be more lenient when checking the hotspot for scaled icons to account for the restriction
+        // that bitmaps must have an integer size.
+        if (hotSpotX < 0 || (isScaled ? (int) hotSpotX > bitmap.getWidth()
+                : hotSpotX >= bitmap.getWidth())) {
             throw new IllegalArgumentException("x hotspot lies outside of the bitmap area");
         }
-        if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) {
+        if (hotSpotY < 0 || (isScaled ? (int) hotSpotY > bitmap.getHeight()
+                : hotSpotY >= bitmap.getHeight())) {
             throw new IllegalArgumentException("y hotspot lies outside of the bitmap area");
         }
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ba6d5df..9aa723a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27294,7 +27294,9 @@
      * @return a view with given ID if found, or {@code null} otherwise
      * @see View#requireViewById(int)
      */
-    /* TODO(b/347672184): Re-add @Nullable */
+    // Strictly speaking this should be marked as @Nullable but the nullability of the return value
+    // is deliberately left unspecified as idiomatically correct code can make assumptions either
+    // way based on local context, e.g. layout specification.
     public final <T extends View> T findViewById(@IdRes int id) {
         if (id == NO_ID) {
             return null;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index bfdcd59..50cf5a5f 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1712,7 +1712,9 @@
      * @see View#findViewById(int)
      * @see Window#requireViewById(int)
      */
-    /* TODO(b/347672184): Re-add @Nullable */
+    // Strictly speaking this should be marked as @Nullable but the nullability of the return value
+    // is deliberately left unspecified as idiomatically correct code can make assumptions either
+    // way based on local context, e.g. layout specification.
     public <T extends View> T findViewById(@IdRes int id) {
         return getDecorView().findViewById(id);
     }
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
index 78c8881..297c490 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
@@ -5,7 +5,7 @@
      android:versionCode="1"
      android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="8"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="18"/>
 
     <application android:name="com.android.multidexlegacyandexception.TestApplication"
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml
index 1a60c1e..a208268 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml
@@ -5,7 +5,7 @@
      android:versionCode="1"
      android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="8"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="18"/>
 
     <application android:name=".TestApplication"
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml
index 35369c7..bb2a201 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests/AndroidManifest.xml
@@ -4,7 +4,7 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="8" />
+    <uses-sdk android:minSdkVersion="21" />
     <instrumentation
         android:name="com.android.test.runner.MultiDexTestRunner"
         android:targetPackage="com.android.multidexlegacytestapp" />
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml
index 1cadfcd..b96566c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/AndroidManifest.xml
@@ -4,7 +4,7 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="8" />
+    <uses-sdk android:minSdkVersion="21" />
     <instrumentation
         android:name="com.android.multidexlegacytestapp.test2.MultiDexAndroidJUnitRunner"
         android:targetPackage="com.android.multidexlegacytestapp" />
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml
index e2fba4e..c644c36 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/AndroidManifest.xml
@@ -4,7 +4,7 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="9" />
+    <uses-sdk android:minSdkVersion="21" />
     <instrumentation
         android:name="android.test.InstrumentationTestRunner"
         android:targetPackage="com.android.framework.multidexlegacytestservices" />
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
index 01285e7..f511c5f 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
@@ -4,7 +4,7 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="9" />
+    <uses-sdk android:minSdkVersion="21" />
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
index 8c911c4..4730243 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
@@ -5,7 +5,7 @@
      android:versionCode="1"
      android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="18"/>
 
     <application android:name="androidx.multidex.MultiDexApplication"
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
index 1817e95..0bcf9fe 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
@@ -5,7 +5,7 @@
      android:versionCode="2"
      android:versionName="2.0">
 
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="18"/>
 
     <application android:name="androidx.multidex.MultiDexApplication"
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
index c8a41bc..5b7680d 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
@@ -5,7 +5,7 @@
      android:versionCode="3"
      android:versionName="3.0">
 
-    <uses-sdk android:minSdkVersion="9"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="18"/>
 
     <application android:name="androidx.multidex.MultiDexApplication"
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 65615e6..7b96699 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -325,10 +325,12 @@
     <!-- These are the standard packages that are allowed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
     <allow-in-power-save package="com.android.providers.downloads" />
+    <allow-in-power-save package="com.android.rkpdapp" />
 
     <!-- These are the standard packages that are allowed to always have internet
          access while in data mode, even if they aren't in the foreground. -->
     <allow-in-data-usage-save package="com.android.providers.downloads" />
+    <allow-in-data-usage-save package="com.android.rkpdapp" />
 
     <!-- This is a core platform component that needs to freely run in the background -->
     <allow-in-power-save package="com.android.cellbroadcastreceiver.module" />
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 4b367e0..f9fd369 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -66,6 +66,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.security.auth.x500.X500Principal;
@@ -376,6 +377,8 @@
      */
     public static final int KEY_ATTESTATION_FAILURE = 4;
 
+    private static final int BIND_KEY_CHAIN_SERVICE_TIMEOUT_MS = 30 * 1000;
+
     /**
      * Used by DPC or delegated app in
      * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias} or
@@ -1120,7 +1123,10 @@
             context.unbindService(keyChainServiceConnection);
             throw new AssertionError("could not bind to KeyChainService");
         }
-        countDownLatch.await();
+        if (!countDownLatch.await(BIND_KEY_CHAIN_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            context.unbindService(keyChainServiceConnection);
+            throw new AssertionError("binding to KeyChainService timeout");
+        }
         IKeyChainService service = keyChainService.get();
         if (service != null) {
             return new KeyChainConnection(context, keyChainServiceConnection, service);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 293c561..47adde4 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1636,7 +1636,8 @@
     /** @hide */ public static final int FORCE_ENCODED_SURROUND_NEVER = 13;
     /** @hide */ public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14;
     /** @hide */ public static final int FORCE_ENCODED_SURROUND_MANUAL = 15;
-    /** @hide */ public static final int NUM_FORCE_CONFIG = 16;
+    /** @hide */ public static final int FORCE_BT_BLE = 16;
+    /** @hide */ public static final int NUM_FORCE_CONFIG = 17;
     /** @hide */ public static final int FORCE_DEFAULT = FORCE_NONE;
 
     /** @hide */
@@ -1658,6 +1659,7 @@
             case FORCE_ENCODED_SURROUND_NEVER: return "FORCE_ENCODED_SURROUND_NEVER";
             case FORCE_ENCODED_SURROUND_ALWAYS: return "FORCE_ENCODED_SURROUND_ALWAYS";
             case FORCE_ENCODED_SURROUND_MANUAL: return "FORCE_ENCODED_SURROUND_MANUAL";
+            case FORCE_BT_BLE: return "FORCE_BT_BLE";
             default: return "unknown config (" + config + ")" ;
         }
     }
diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml
index c18efa2..b24639c 100644
--- a/media/tests/SoundPoolTest/AndroidManifest.xml
+++ b/media/tests/SoundPoolTest/AndroidManifest.xml
@@ -12,6 +12,6 @@
             </intent-filter>
         </activity>
     </application>
-    <uses-sdk android:minSdkVersion="8"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="8"/>
 </manifest>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
index 8dd51b2..8de0c35 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
@@ -22,8 +22,6 @@
 
 import android.content.ContentResolver;
 import android.os.Bundle;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
@@ -73,24 +71,9 @@
     }
 
     /**
-     * Test that setting overrides are properly disabled when the flag is off.
-     */
-    @Test
-    @RequiresFlagsDisabled("com.android.providers.settings.support_overrides")
-    public void testOverrideDisabled() throws IOException {
-        final String newValue = "value2";
-
-        executeShellCommand("device_config put " + sNamespace + " " + sKey + " " + sValue);
-        executeShellCommand("device_config override " + sNamespace + " " + sKey + " " + newValue);
-        String result = readShellCommandOutput("device_config get " + sNamespace + " " + sKey);
-        assertEquals(sValue + "\n", result);
-    }
-
-    /**
      * Test that overrides are readable and can be cleared.
      */
     @Test
-    @RequiresFlagsEnabled("com.android.providers.settings.support_overrides")
     public void testOverride() throws IOException {
         final String newValue = "value2";
 
diff --git a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java
index e605514..2009cd3 100644
--- a/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java
+++ b/services/accessibility/java/com/android/server/accessibility/FlashNotificationsController.java
@@ -659,6 +659,8 @@
                 mIsTorchTouched = on;
             } catch (CameraAccessException e) {
                 Log.e(LOG_TAG, "Failed to setTorchMode: " + e);
+            } catch (IllegalArgumentException  e) {
+                Log.e(LOG_TAG, "Failed to setTorchMode: " + e);
             }
         } else {
             Log.e(LOG_TAG, "Can not use camera flash notification, please check CameraManager!");
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index f1eea72..33ad49e 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -787,6 +787,14 @@
         return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
     }
 
+    /*package*/ boolean isBluetoothBleHeadsetActive() {
+        return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET);
+    }
+
+    /*package*/ boolean isBluetoothBleSpeakerActive() {
+        return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER);
+    }
+
     /*package*/ boolean isDeviceConnected(@NonNull AudioDeviceAttributes device) {
         synchronized (mDeviceStateLock) {
             return mDeviceInventory.isDeviceConnected(device);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3f49b90..6787fa6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5665,16 +5665,25 @@
                 || ringerMode == AudioManager.RINGER_MODE_SILENT;
         final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE
                 && mDeviceBroker.isBluetoothScoActive();
-        // Ask audio policy engine to force use Bluetooth SCO channel if needed
+        final boolean shouldRingBle = ringerMode == AudioManager.RINGER_MODE_VIBRATE
+                && (mDeviceBroker.isBluetoothBleHeadsetActive()
+                || mDeviceBroker.isBluetoothBleSpeakerActive());
+        // Ask audio policy engine to force use Bluetooth SCO/BLE channel if needed
         final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid()
                 + "/" + Binder.getCallingPid();
+        int forceUse = AudioSystem.FORCE_NONE;
+        if (shouldRingSco) {
+            forceUse = AudioSystem.FORCE_BT_SCO;
+        } else if (shouldRingBle) {
+            forceUse = AudioSystem.FORCE_BT_BLE;
+        }
         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_VIBRATE_RINGING,
-                shouldRingSco ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE, eventSource, 0);
+                forceUse, eventSource, 0);
 
         for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
             final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType);
             final boolean muteAllowedBySco =
-                    !(shouldRingSco && streamType == AudioSystem.STREAM_RING);
+                    !((shouldRingSco || shouldRingBle) && streamType == AudioSystem.STREAM_RING);
             final boolean shouldZenMute = isStreamAffectedByCurrentZen(streamType);
             final boolean shouldMute = shouldZenMute || (ringerModeMute
                     && isStreamAffectedByRingerMode(streamType) && muteAllowedBySco);
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index c8bc56c..9b0616a 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -28,6 +28,7 @@
 per-file RestrictionsSet.java = file:MULTIUSER_AND_ENTERPRISE_OWNERS
 per-file UserRestriction* = file:MULTIUSER_AND_ENTERPRISE_OWNERS
 per-file User* = file:/MULTIUSER_OWNERS
+per-file BackgroundUser* = file:/MULTIUSER_OWNERS
 
 # security
 per-file KeySetHandle.java = cbrubaker@google.com, nnk@google.com
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml
index 3363af4..27a8b2a 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/AndroidManifest.xml
@@ -18,7 +18,7 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" />
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="17" />
 
     <instrumentation
         android:name="android.test.InstrumentationTestRunner"
diff --git a/tests/HugeBackup/AndroidManifest.xml b/tests/HugeBackup/AndroidManifest.xml
index 945e59b..92445dd 100644
--- a/tests/HugeBackup/AndroidManifest.xml
+++ b/tests/HugeBackup/AndroidManifest.xml
@@ -25,7 +25,7 @@
      android:versionName="1.0">
 
     <!-- The backup/restore mechanism was introduced in API version 8 -->
-    <uses-sdk android:minSdkVersion="8"
+    <uses-sdk android:minSdkVersion="21"
          android:targetSdkVersion="8"/>
 
     <application android:label="Huge Backup"
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 031dd5b..9b8c3b3 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -836,6 +836,28 @@
     return 1;
   }
 
+  // Parse the feature flag values. An argument that starts with '@' points to a file to read flag
+  // values from.
+  std::vector<std::string> all_feature_flags_args;
+  for (const std::string& arg : feature_flags_args_) {
+    if (util::StartsWith(arg, "@")) {
+      const std::string path = arg.substr(1, arg.size() - 1);
+      std::string error;
+      if (!file::AppendArgsFromFile(path, &all_feature_flags_args, &error)) {
+        context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
+        return 1;
+      }
+    } else {
+      all_feature_flags_args.push_back(arg);
+    }
+  }
+
+  for (const std::string& arg : all_feature_flags_args) {
+    if (!ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) {
+      return 1;
+    }
+  }
+
   return Compile(&context, file_collection.get(), archive_writer.get(), options_);
 }
 
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index 61c5b60..70c8791 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -24,6 +24,7 @@
 #include "Command.h"
 #include "ResourceTable.h"
 #include "androidfw/IDiagnostics.h"
+#include "cmd/Util.h"
 #include "format/Archive.h"
 #include "process/IResourceTableConsumer.h"
 
@@ -45,6 +46,7 @@
   bool preserve_visibility_of_styleables = false;
   bool verbose = false;
   std::optional<std::string> product_;
+  FeatureFlagValues feature_flag_values;
 };
 
 /** Parses flags and compiles resources to be used in linking.  */
@@ -92,6 +94,12 @@
                     "Leave only resources specific to the given product. All "
                     "other resources (including defaults) are removed.",
                     &options_.product_);
+    AddOptionalFlagList("--feature-flags",
+                        "Specify the values of feature flags. The pairs in the argument\n"
+                        "are separated by ',' the name is separated from the value by '='.\n"
+                        "The name can have a suffix of ':ro' to indicate it is read only."
+                        "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).",
+                        &feature_flags_args_);
   }
 
   int Action(const std::vector<std::string>& args) override;
@@ -101,6 +109,7 @@
   CompileOptions options_;
   std::optional<std::string> visibility_;
   std::optional<std::string> trace_folder_;
+  std::vector<std::string> feature_flags_args_;
 };
 
 int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer,
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 8fe414f..2f17853 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -332,8 +332,9 @@
     AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
     AddOptionalFlagList("--feature-flags",
                         "Specify the values of feature flags. The pairs in the argument\n"
-                        "are separated by ',' and the name is separated from the value by '='.\n"
-                        "Example: \"flag1=true,flag2=false,flag3=\" (flag3 has no given value).",
+                        "are separated by ',' the name is separated from the value by '='.\n"
+                        "The name can have a suffix of ':ro' to indicate it is read only."
+                        "Example: \"flag1=true,flag2:ro=false,flag3=\" (flag3 has no given value).",
                         &feature_flags_args_);
     AddOptionalSwitch("--non-updatable-system",
                       "Mark the app as a non-updatable system app. This inserts\n"
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 678d846..e839fc1 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -128,7 +128,7 @@
     if (parts.size() > 2) {
       diag->Error(android::DiagMessage()
                   << "Invalid feature flag and optional value '" << flag_and_value
-                  << "'. Must be in the format 'flag_name[=true|false]");
+                  << "'. Must be in the format 'flag_name[:ro][=true|false]");
       return false;
     }
 
@@ -137,6 +137,25 @@
       diag->Error(android::DiagMessage() << "No name given for one or more flags in: " << arg);
       return false;
     }
+    std::vector<std::string> name_parts = util::Split(flag_name, ':');
+    if (name_parts.size() > 2) {
+      diag->Error(android::DiagMessage()
+                  << "Invalid feature flag and optional value '" << flag_and_value
+                  << "'. Must be in the format 'flag_name[:ro][=true|false]");
+      return false;
+    }
+    flag_name = name_parts[0];
+    bool read_only = false;
+    if (name_parts.size() == 2) {
+      if (name_parts[1] == "ro") {
+        read_only = true;
+      } else {
+        diag->Error(android::DiagMessage()
+                    << "Invalid feature flag and optional value '" << flag_and_value
+                    << "'. Must be in the format 'flag_name[:ro][=true|false]");
+        return false;
+      }
+    }
 
     std::optional<bool> flag_value = {};
     if (parts.size() == 2) {
@@ -151,13 +170,13 @@
       }
     }
 
-    if (auto [it, inserted] =
-            out_feature_flag_values->try_emplace(std::string(flag_name), flag_value);
+    auto ffp = FeatureFlagProperties{read_only, flag_value};
+    if (auto [it, inserted] = out_feature_flag_values->try_emplace(std::string(flag_name), ffp);
         !inserted) {
       // We are allowing the same flag to appear multiple times, last value wins.
       diag->Note(android::DiagMessage()
                  << "Value for feature flag '" << flag_name << "' was given more than once");
-      it->second = flag_value;
+      it->second = ffp;
     }
   }
   return true;
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index 9ece5dd..6b8813b 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -37,7 +37,17 @@
 
 namespace aapt {
 
-using FeatureFlagValues = std::map<std::string, std::optional<bool>, std::less<>>;
+struct FeatureFlagProperties {
+  bool read_only;
+  std::optional<bool> enabled;
+
+  FeatureFlagProperties(bool ro, std::optional<bool> e) : read_only(ro), enabled(e) {
+  }
+
+  bool operator==(const FeatureFlagProperties&) const = default;
+};
+
+using FeatureFlagValues = std::map<std::string, FeatureFlagProperties, std::less<>>;
 
 // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc).
 // Returns Nothing and logs a human friendly error message if the string was not legal.
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index 723d87e..35bc637 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -383,21 +383,25 @@
 TEST(UtilTest, ParseFeatureFlagsParameter_DuplicateFlag) {
   auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics();
   FeatureFlagValues feature_flag_values;
-  ASSERT_TRUE(
-      ParseFeatureFlagsParameter("foo=true,bar=true,foo=false", diagnostics, &feature_flag_values));
-  EXPECT_THAT(feature_flag_values, UnorderedElementsAre(Pair("foo", std::optional<bool>(false)),
-                                                        Pair("bar", std::optional<bool>(true))));
+  ASSERT_TRUE(ParseFeatureFlagsParameter("foo=true,bar=true,foo:ro=false", diagnostics,
+                                         &feature_flag_values));
+  EXPECT_THAT(
+      feature_flag_values,
+      UnorderedElementsAre(Pair("foo", FeatureFlagProperties{true, std::optional<bool>(false)}),
+                           Pair("bar", FeatureFlagProperties{false, std::optional<bool>(true)})));
 }
 
 TEST(UtilTest, ParseFeatureFlagsParameter_Valid) {
   auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics();
   FeatureFlagValues feature_flag_values;
-  ASSERT_TRUE(ParseFeatureFlagsParameter("foo= true, bar =FALSE,baz=, quux", diagnostics,
+  ASSERT_TRUE(ParseFeatureFlagsParameter("foo= true, bar:ro =FALSE,baz=, quux", diagnostics,
                                          &feature_flag_values));
-  EXPECT_THAT(feature_flag_values,
-              UnorderedElementsAre(Pair("foo", std::optional<bool>(true)),
-                                   Pair("bar", std::optional<bool>(false)),
-                                   Pair("baz", std::nullopt), Pair("quux", std::nullopt)));
+  EXPECT_THAT(
+      feature_flag_values,
+      UnorderedElementsAre(Pair("foo", FeatureFlagProperties{false, std::optional<bool>(true)}),
+                           Pair("bar", FeatureFlagProperties{true, std::optional<bool>(false)}),
+                           Pair("baz", FeatureFlagProperties{false, std::nullopt}),
+                           Pair("quux", FeatureFlagProperties{false, std::nullopt})));
 }
 
 TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
diff --git a/tools/aapt2/link/FeatureFlagsFilter.cpp b/tools/aapt2/link/FeatureFlagsFilter.cpp
index fdf3f74..9d40db5 100644
--- a/tools/aapt2/link/FeatureFlagsFilter.cpp
+++ b/tools/aapt2/link/FeatureFlagsFilter.cpp
@@ -63,12 +63,11 @@
         flag_name = flag_name.substr(1);
       }
 
-      if (auto it = feature_flag_values_.find(std::string(flag_name));
-          it != feature_flag_values_.end()) {
-        if (it->second.has_value()) {
+      if (auto it = feature_flag_values_.find(flag_name); it != feature_flag_values_.end()) {
+        if (it->second.enabled.has_value()) {
           if (options_.remove_disabled_elements) {
             // Remove if flag==true && attr=="!flag" (negated) OR flag==false && attr=="flag"
-            return *it->second == negated;
+            return *it->second.enabled == negated;
           }
         } else if (options_.flags_must_have_value) {
           diagnostics_->Error(android::DiagMessage(node->line_number)
diff --git a/tools/aapt2/link/FeatureFlagsFilter_test.cpp b/tools/aapt2/link/FeatureFlagsFilter_test.cpp
index 53086cc..2db2899 100644
--- a/tools/aapt2/link/FeatureFlagsFilter_test.cpp
+++ b/tools/aapt2/link/FeatureFlagsFilter_test.cpp
@@ -48,7 +48,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" />
     </manifest>)EOF",
-                    {{"flag", false}});
+                    {{"flag", FeatureFlagProperties{false, false}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -60,7 +60,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="flag" />
     </manifest>)EOF",
-                    {{"flag", false}});
+                    {{"flag", FeatureFlagProperties{false, false}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -73,7 +73,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="!flag" />
     </manifest>)EOF",
-                    {{"flag", true}});
+                    {{"flag", FeatureFlagProperties{false, true}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -86,7 +86,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="flag" />
     </manifest>)EOF",
-                    {{"flag", true}});
+                    {{"flag", FeatureFlagProperties{false, true}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -102,7 +102,7 @@
       <permission android:name="FOO" android:featureFlag="flag"
                   android:protectionLevel="dangerous" />
     </manifest>)EOF",
-                    {{"flag", true}});
+                    {{"flag", FeatureFlagProperties{false, true}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -123,7 +123,7 @@
         </activity>
       </application>
     </manifest>)EOF",
-                    {{"flag", true}});
+                    {{"flag", FeatureFlagProperties{false, true}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -145,7 +145,7 @@
         </activity>
       </application>
     </manifest>)EOF",
-                    {{"flag", true}});
+                    {{"flag", FeatureFlagProperties{false, true}}});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -162,7 +162,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag=" " />
     </manifest>)EOF",
-                    {{"flag", false}});
+                    {{"flag", FeatureFlagProperties{false, false}}});
   ASSERT_THAT(doc, IsNull());
 }
 
@@ -171,7 +171,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="flag" />
     </manifest>)EOF",
-                    {{"flag", std::nullopt}});
+                    {{"flag", FeatureFlagProperties{false, std::nullopt}}});
   ASSERT_THAT(doc, IsNull());
 }
 
@@ -180,7 +180,7 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="unrecognized" />
     </manifest>)EOF",
-                    {{"flag", true}});
+                    {{"flag", FeatureFlagProperties{false, true}}});
   ASSERT_THAT(doc, IsNull());
 }
 
@@ -190,7 +190,7 @@
       <permission android:name="FOO" android:featureFlag="bar" />
       <permission android:name="FOO" android:featureFlag="unrecognized" />
     </manifest>)EOF",
-                    {{"flag", std::nullopt}});
+                    {{"flag", FeatureFlagProperties{false, std::nullopt}}});
   ASSERT_THAT(doc, IsNull());
 }
 
@@ -199,7 +199,8 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="flag" />
     </manifest>)EOF",
-                               {{"flag", false}}, {.remove_disabled_elements = false});
+                               {{"flag", FeatureFlagProperties{false, false}}},
+                               {.remove_disabled_elements = false});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -212,7 +213,8 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="flag" />
     </manifest>)EOF",
-                               {{"flag", std::nullopt}}, {.flags_must_have_value = false});
+                               {{"flag", FeatureFlagProperties{false, std::nullopt}}},
+                               {.flags_must_have_value = false});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
@@ -225,7 +227,8 @@
     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android">
       <permission android:name="FOO" android:featureFlag="unrecognized" />
     </manifest>)EOF",
-                               {{"flag", true}}, {.fail_on_unrecognized_flags = false});
+                               {{"flag", FeatureFlagProperties{false, true}}},
+                               {.fail_on_unrecognized_flags = false});
   ASSERT_THAT(doc, NotNull());
   auto root = doc->root.get();
   ASSERT_THAT(root, NotNull());
diff --git a/tools/lint/fix/README.md b/tools/lint/fix/README.md
index a5ac2be..18bda92 100644
--- a/tools/lint/fix/README.md
+++ b/tools/lint/fix/README.md
@@ -6,7 +6,7 @@
 
 It's a python script that runs the framework linter,
 and then (optionally) copies modified files back into the source tree.\
-Why python, you ask?  Because python is cool ¯\_(ツ)_/¯.
+Why python, you ask? Because python is cool ¯\\\_(ツ)\_/¯.
 
 Incidentally, this exposes a much simpler way to run individual lint checks
 against individual modules, so it's useful beyond applying fixes.
@@ -15,7 +15,7 @@
 
 Lint is not allowed to modify source files directly via lint's `--apply-suggestions` flag.
 As a compromise, soong zips up the (potentially) modified sources and leaves them in an intermediate
-directory.  This script runs the lint, unpacks those files, and copies them back into the tree.
+directory. This script runs the lint, unpacks those files, and copies them back into the tree.
 
 ## How do I run it?
 **WARNING: You probably want to commit/stash any changes to your working tree before doing this...**