Merge "freezer: add internal per-process callbacks" into main
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 22804a2..0c786cb 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FastPrintWriter;
 
 import java.lang.annotation.Retention;
@@ -1260,7 +1261,7 @@
         }
 
         public void autoCork() {
-            if (Looper.getMainLooper() == null) {
+            if (getLooper() == null) {
                 // We're not ready to auto-cork yet, so just invalidate the cache immediately.
                 if (DEBUG) {
                     Log.w(TAG, "invalidating instead of autocorking early in init: "
@@ -1322,7 +1323,7 @@
         @GuardedBy("mLock")
         private Handler getHandlerLocked() {
             if (mHandler == null) {
-                mHandler = new Handler(Looper.getMainLooper()) {
+                mHandler = new Handler(getLooper()) {
                         @Override
                         public void handleMessage(Message msg) {
                             AutoCorker.this.handleMessage(msg);
@@ -1331,6 +1332,14 @@
             }
             return mHandler;
         }
+
+        /**
+         * Return a looper for auto-uncork messages.  Messages should be processed on the
+         * background thread, not on the main thread.
+         */
+        private static Looper getLooper() {
+            return BackgroundThread.getHandler().getLooper();
+        }
     }
 
     /**
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index af0272e..df288f9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3065,10 +3065,13 @@
         frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
     <integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 1+4+8 -->
 
-    <!-- Whether the main user is a permanent admin user. If the main user is a permanent admin user
-     it can't be deleted or downgraded to non-admin status.
-     This is generally only relevant on headless system user mode devices; on other devices, the
-     main user is the system user which is always a permanent admin anyway. -->
+    <!-- Whether the device will automatically (at first boot) have a designated main user and treat
+         it as a permanent admin.
+         Since the main user is a permanent admin user it can't be deleted or downgraded to
+         non-admin status.
+         This is generally only relevant on headless system user mode (HSUM) devices; on other
+         devices, the main user is the system user which is always a permanent admin anyway.
+         Note that HSUM devices without this enabled will not automatically have a main user. -->
     <bool name="config_isMainUserPermanentAdmin">true</bool>
 
     <!-- Whether switch to headless system user is allowed. If allowed,
@@ -3079,7 +3082,7 @@
     <bool name="config_enableMultiUserUI">false</bool>
 
     <!-- Whether multiple admins are allowed on the device. If set to true, new users can be created
-     with admin privileges and admin privileges can be granted/revoked from existing users. -->
+         with admin privileges and admin privileges can be granted/revoked from existing users. -->
     <bool name="config_enableMultipleAdmins">false</bool>
 
     <!-- Whether there is a communal profile which should always be running.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
index cd442cf..99ed2d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
@@ -21,7 +21,6 @@
 import android.telephony.TelephonyManager.EXTRA_PLMN
 import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
 import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
-import android.telephony.TelephonyManager.EXTRA_SPN
 import com.android.systemui.log.table.Diffable
 import com.android.systemui.log.table.TableRowLogger
 
@@ -97,8 +96,7 @@
 
 fun Intent.toNetworkNameModel(separator: String): NetworkNameModel? {
     val showSpn = getBooleanExtra(EXTRA_SHOW_SPN, false)
-    val spn = getStringExtra(EXTRA_SPN)
-    val dataSpn = getStringExtra(EXTRA_DATA_SPN)
+    val spn = getStringExtra(EXTRA_DATA_SPN)
     val showPlmn = getBooleanExtra(EXTRA_SHOW_PLMN, false)
     val plmn = getStringExtra(EXTRA_PLMN)
 
@@ -114,12 +112,6 @@
         }
         str.append(spn)
     }
-    if (showSpn && dataSpn != null) {
-        if (str.isNotEmpty()) {
-            str.append(separator)
-        }
-        str.append(dataSpn)
-    }
 
     return if (str.isNotEmpty()) NetworkNameModel.IntentDerived(str.toString()) else null
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 9d83d5f..8fd0b31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -59,7 +59,6 @@
 import android.telephony.TelephonyManager.ERI_OFF
 import android.telephony.TelephonyManager.ERI_ON
 import android.telephony.TelephonyManager.EXTRA_CARRIER_ID
-import android.telephony.TelephonyManager.EXTRA_DATA_SPN
 import android.telephony.TelephonyManager.EXTRA_PLMN
 import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
 import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
@@ -86,6 +85,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
@@ -93,6 +93,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.mockito.withArgCaptor
@@ -110,8 +112,6 @@
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
-import org.mockito.kotlin.any
-import org.mockito.kotlin.argumentCaptor
 
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -815,11 +815,9 @@
             val intent = spnIntent()
             val captor = argumentCaptor<BroadcastReceiver>()
             verify(context).registerReceiver(captor.capture(), any())
-            captor.lastValue.onReceive(context, intent)
+            captor.value!!.onReceive(context, intent)
 
-            // spnIntent() sets all values to true and test strings
-            assertThat(latest)
-                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN$SEP$DATA_SPN"))
+            assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
             job.cancel()
         }
@@ -833,19 +831,17 @@
             val intent = spnIntent()
             val captor = argumentCaptor<BroadcastReceiver>()
             verify(context).registerReceiver(captor.capture(), any())
-            captor.lastValue.onReceive(context, intent)
+            captor.value!!.onReceive(context, intent)
 
-            assertThat(latest)
-                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN$SEP$DATA_SPN"))
+            assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
             // WHEN an intent with a different subId is sent
             val wrongSubIntent = spnIntent(subId = 101)
 
-            captor.lastValue.onReceive(context, wrongSubIntent)
+            captor.value!!.onReceive(context, wrongSubIntent)
 
             // THEN the previous intent's name is still used
-            assertThat(latest)
-                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN$SEP$DATA_SPN"))
+            assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
             job.cancel()
         }
@@ -859,10 +855,9 @@
             val intent = spnIntent()
             val captor = argumentCaptor<BroadcastReceiver>()
             verify(context).registerReceiver(captor.capture(), any())
-            captor.lastValue.onReceive(context, intent)
+            captor.value!!.onReceive(context, intent)
 
-            assertThat(latest)
-                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN$SEP$DATA_SPN"))
+            assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
             val intentWithoutInfo =
                 spnIntent(
@@ -870,7 +865,7 @@
                     showPlmn = false,
                 )
 
-            captor.lastValue.onReceive(context, intentWithoutInfo)
+            captor.value!!.onReceive(context, intentWithoutInfo)
 
             assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
 
@@ -889,88 +884,10 @@
             val intent = spnIntent()
             val captor = argumentCaptor<BroadcastReceiver>()
             verify(context).registerReceiver(captor.capture(), any())
-            captor.lastValue.onReceive(context, intent)
+            captor.value!!.onReceive(context, intent)
 
             // The value is still there despite no active subscribers
-            assertThat(underTest.networkName.value)
-                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN$SEP$DATA_SPN"))
-        }
-
-    @Test
-    fun networkName_allFieldsSet() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.networkName)
-            val captor = argumentCaptor<BroadcastReceiver>()
-            verify(context).registerReceiver(captor.capture(), any())
-
-            val intent =
-                spnIntent(
-                    subId = SUB_1_ID,
-                    showSpn = true,
-                    spn = SPN,
-                    dataSpn = null,
-                    showPlmn = true,
-                    plmn = PLMN,
-                )
-            captor.lastValue.onReceive(context, intent)
-            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
-        }
-
-    @Test
-    fun networkName_showPlmn_plmnNotNull_showSpn_spnNull_dataSpnNotNull() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.networkName)
-            val captor = argumentCaptor<BroadcastReceiver>()
-            verify(context).registerReceiver(captor.capture(), any())
-            val intent =
-                spnIntent(
-                    subId = SUB_1_ID,
-                    showSpn = true,
-                    spn = null,
-                    dataSpn = DATA_SPN,
-                    showPlmn = true,
-                    plmn = PLMN,
-                )
-            captor.lastValue.onReceive(context, intent)
-            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
-        }
-
-    @Test
-    fun networkName_showPlmn_noShowSPN() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.networkName)
-            val captor = argumentCaptor<BroadcastReceiver>()
-            verify(context).registerReceiver(captor.capture(), any())
-            val intent =
-                spnIntent(
-                    subId = SUB_1_ID,
-                    showSpn = false,
-                    spn = SPN,
-                    dataSpn = DATA_SPN,
-                    showPlmn = true,
-                    plmn = PLMN,
-                )
-            captor.lastValue.onReceive(context, intent)
-            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN"))
-        }
-
-    @Test
-    fun networkName_showPlmn_plmnNull_showSpn() =
-        testScope.runTest {
-            val latest by collectLastValue(underTest.networkName)
-            val captor = argumentCaptor<BroadcastReceiver>()
-            verify(context).registerReceiver(captor.capture(), any())
-            val intent =
-                spnIntent(
-                    subId = SUB_1_ID,
-                    showSpn = true,
-                    spn = SPN,
-                    dataSpn = DATA_SPN,
-                    showPlmn = true,
-                    plmn = null,
-                )
-            captor.lastValue.onReceive(context, intent)
-            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$SPN$SEP$DATA_SPN"))
+            assertThat(underTest.networkName.value).isEqualTo(intent.toNetworkNameModel(SEP))
         }
 
     @Test
@@ -1211,16 +1128,14 @@
     private fun spnIntent(
         subId: Int = SUB_1_ID,
         showSpn: Boolean = true,
-        spn: String? = SPN,
-        dataSpn: String? = DATA_SPN,
+        spn: String = SPN,
         showPlmn: Boolean = true,
-        plmn: String? = PLMN,
+        plmn: String = PLMN,
     ): Intent =
         Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply {
             putExtra(EXTRA_SUBSCRIPTION_INDEX, subId)
             putExtra(EXTRA_SHOW_SPN, showSpn)
             putExtra(EXTRA_SPN, spn)
-            putExtra(EXTRA_DATA_SPN, dataSpn)
             putExtra(EXTRA_SHOW_PLMN, showPlmn)
             putExtra(EXTRA_PLMN, plmn)
         }
@@ -1233,7 +1148,6 @@
         private const val SEP = "-"
 
         private const val SPN = "testSpn"
-        private const val DATA_SPN = "testDataSpn"
         private const val PLMN = "testPlmn"
     }
 }
diff --git a/packages/overlays/HsumConfigOverlay/Android.bp b/packages/overlays/HsumConfigOverlay/Android.bp
new file mode 100644
index 0000000..050b1f0
--- /dev/null
+++ b/packages/overlays/HsumConfigOverlay/Android.bp
@@ -0,0 +1,16 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+runtime_resource_overlay {
+    name: "HsumConfigOverlay",
+    certificate: "platform",
+
+    product_specific: true,
+    sdk_version: "current",
+}
diff --git a/packages/overlays/HsumConfigOverlay/AndroidManifest.xml b/packages/overlays/HsumConfigOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..cd7a879
--- /dev/null
+++ b/packages/overlays/HsumConfigOverlay/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.internal.overlay.hsumconfig"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="android" android:priority="2" android:isStatic="true" />
+</manifest>
diff --git a/packages/overlays/HsumConfigOverlay/OWNERS b/packages/overlays/HsumConfigOverlay/OWNERS
new file mode 100644
index 0000000..79dd1c9
--- /dev/null
+++ b/packages/overlays/HsumConfigOverlay/OWNERS
@@ -0,0 +1,2 @@
+# People who can approve submission
+include platform/frameworks/base:/MULTIUSER_OWNERS
diff --git a/packages/overlays/HsumConfigOverlay/res/values/config.xml b/packages/overlays/HsumConfigOverlay/res/values/config.xml
new file mode 100644
index 0000000..7dbdfc7
--- /dev/null
+++ b/packages/overlays/HsumConfigOverlay/res/values/config.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Default configuration for Headless System User Mode (HSUM) builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+  <!-- Whether multiple admins are allowed on the device. If set to true, new users can be created
+       with admin privileges and admin privileges can be granted/revoked from existing users. -->
+  <bool name="config_enableMultipleAdmins">true</bool>
+
+  <!-- Whether the device will automatically (at first boot) have a designated main user and treat
+       it as a permanent admin.
+       Since the main user is a permanent admin user it can't be deleted or downgraded to
+       non-admin status.
+       This is generally only relevant on headless system user mode (HSUM) devices; on other
+       devices, the main user is the system user which is always a permanent admin anyway.
+       Note that HSUM devices without this enabled will not automatically have a main user. -->
+  <bool name="config_isMainUserPermanentAdmin">true</bool>
+
+  <!-- Maximum number of users we allow to be running at a time.
+       Note that this includes the headless system user. -->
+  <integer name="config_multiuserMaxRunningUsers">4</integer>
+
+</resources>
diff --git a/services/Android.bp b/services/Android.bp
index dce6aa7..ded7379 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -108,6 +108,8 @@
 filegroup {
     name: "services-non-updatable-sources",
     srcs: [
+        ":incremental_aidl",
+        ":services.core-aidl-sources",
         ":services.core-sources",
         ":services.core-sources-am-wm",
         "core/java/com/android/server/am/package.html",
@@ -377,4 +379,8 @@
         },
     },
     api_surface: "system-server",
+    sdk_version: "module_current",
+    libs: [
+        "framework-annotations-lib",
+    ],
 }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 363c1d8..89d7961 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -30,6 +30,18 @@
     ],
 }
 
+filegroup {
+    name: "services.core-aidl-sources",
+    srcs: [
+        ":dumpstate_aidl",
+        ":framework_native_aidl",
+        ":gsiservice_aidl",
+        ":installd_aidl",
+        ":storaged_aidl",
+        ":vold_aidl",
+    ],
+}
+
 java_library_static {
     name: "services-config-update",
     srcs: [
@@ -120,14 +132,9 @@
         ":android.hardware.tv.hdmi.earc-V1-java-source",
         ":statslog-art-java-gen",
         ":statslog-contexthub-java-gen",
+        ":services.core-aidl-sources",
         ":services.core-sources",
         ":services.core.protologsrc",
-        ":dumpstate_aidl",
-        ":framework_native_aidl",
-        ":gsiservice_aidl",
-        ":installd_aidl",
-        ":storaged_aidl",
-        ":vold_aidl",
         ":platform-compat-config",
         ":platform-compat-overrides",
         ":display-device-config",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 1ccc48d..2de4482 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -157,7 +157,7 @@
     private int mLastMaxChargingVoltage;
     private int mLastChargeCounter;
     private int mLastBatteryCycleCount;
-    private int mLastCharingState;
+    private int mLastChargingState;
     /**
      * The last seen charging policy. This requires the
      * {@link android.Manifest.permission#BATTERY_STATS} permission and should therefore not be
@@ -555,7 +555,7 @@
                         || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter
                         || mInvalidCharger != mLastInvalidCharger
                         || mHealthInfo.batteryCycleCount != mLastBatteryCycleCount
-                        || mHealthInfo.chargingState != mLastCharingState)) {
+                        || mHealthInfo.chargingState != mLastChargingState)) {
 
             if (mPlugType != mLastPlugType) {
                 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -738,7 +738,7 @@
             mLastBatteryLevelCritical = mBatteryLevelCritical;
             mLastInvalidCharger = mInvalidCharger;
             mLastBatteryCycleCount = mHealthInfo.batteryCycleCount;
-            mLastCharingState = mHealthInfo.chargingState;
+            mLastChargingState = mHealthInfo.chargingState;
         }
     }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fdf0ba6..79e09d7 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2229,7 +2229,7 @@
                     for (Record r : mRecords) {
                         if (r.matchTelephonyCallbackEvent(
                                 TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
-                                && idMatch(r, subId, phoneId)) {
+                                && idMatchRelaxed(r, subId, phoneId)) {
                             try {
                                 r.callback.onPreciseDataConnectionStateChanged(preciseState);
                             } catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ac43e86..53b04df 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2032,8 +2032,11 @@
 
         synchronized (mCachedAbsVolDrivingStreamsLock) {
             mCachedAbsVolDrivingStreams.forEach((dev, stream) -> {
-                mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", /*enabled=*/true,
-                        stream);
+                boolean enabled = true;
+                if (dev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                    enabled = mAvrcpAbsVolSupported;
+                }
+                mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", enabled, stream);
             });
         }
 
@@ -4831,6 +4834,20 @@
     private void onUpdateContextualVolumes() {
         final int streamType = getBluetoothContextualVolumeStream();
 
+        synchronized (mCachedAbsVolDrivingStreamsLock) {
+            mCachedAbsVolDrivingStreams.replaceAll((absDev, stream) -> {
+                boolean enabled = true;
+                if (absDev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                    enabled = mAvrcpAbsVolSupported;
+                }
+                if (stream != streamType) {
+                    mAudioSystem.setDeviceAbsoluteVolumeEnabled(absDev, /*address=*/"",
+                            enabled, streamType);
+                }
+                return streamType;
+            });
+        }
+
         final Set<Integer> deviceTypes = getDeviceSetForStreamDirect(streamType);
         final Set<Integer> absVolumeMultiModeCaseDevices =
                 AudioSystem.intersectionAudioDeviceTypes(
@@ -6450,17 +6467,6 @@
                 // change of mode may require volume to be re-applied on some devices
                 onUpdateContextualVolumes();
 
-                synchronized (mCachedAbsVolDrivingStreamsLock) {
-                    mCachedAbsVolDrivingStreams.replaceAll((absDev, stream) -> {
-                        int streamToDriveAbs = getBluetoothContextualVolumeStream();
-                        if (stream != streamToDriveAbs) {
-                            mAudioSystem.setDeviceAbsoluteVolumeEnabled(absDev, /*address=*/
-                                    "", /*enabled*/true, streamToDriveAbs);
-                        }
-                        return streamToDriveAbs;
-                    });
-                }
-
                 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
                 // connections not started by the application changing the mode when pid changes
                 mDeviceBroker.postSetModeOwner(mode, pid, uid);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java
index 35fae18..b72a34d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuControllerNew.java
@@ -135,8 +135,8 @@
         final RecyclerView recyclerView = contentView
                 .requireViewById(com.android.internal.R.id.list);
         recyclerView.setAdapter(new Adapter(items, selectedIndex, inflater, onClickListener));
-        // Scroll to the currently selected IME.
-        recyclerView.scrollToPosition(selectedIndex);
+        // Scroll to the currently selected IME. This must run after the recycler view is laid out.
+        recyclerView.post(() -> recyclerView.scrollToPosition(selectedIndex));
         // Indicate that the list can be scrolled.
         recyclerView.setScrollIndicators(
                 hasLanguageSettingsButton ? View.SCROLL_INDICATOR_BOTTOM : 0);