Merge "Add connectionless handwriting support to input method info" into main
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index d913581..e290722 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -677,7 +677,7 @@
      * has at least one HTTP or HTTPS data URI pattern defined, and optionally
      * does not define any non-http/https data URI patterns.
      *
-     * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+     * This will check if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
      * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
      * data scheme is "http" or "https".
      *
@@ -718,7 +718,7 @@
         }
 
         // We get here if:
-        //   1) onlyWebSchemes and no non-web schemes were found, i.e success; or
+        //   1) onlyWebSchemes and no non-web schemes were found, i.e. success; or
         //   2) !onlyWebSchemes and no http/https schemes were found, i.e. failure.
         return onlyWebSchemes;
     }
@@ -728,7 +728,7 @@
      *
      * @return True if the filter needs to be automatically verified. False otherwise.
      *
-     * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+     * This will check if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
      * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
      * data scheme is "http" or "https".
      *
diff --git a/core/java/android/content/pm/overlay/OverlayPaths.java b/core/java/android/content/pm/overlay/OverlayPaths.java
index a4db733..bd74b0b 100644
--- a/core/java/android/content/pm/overlay/OverlayPaths.java
+++ b/core/java/android/content/pm/overlay/OverlayPaths.java
@@ -49,6 +49,13 @@
     public static class Builder {
         final OverlayPaths mPaths = new OverlayPaths();
 
+        public Builder() {}
+
+        public Builder(@NonNull OverlayPaths base) {
+            mPaths.mResourceDirs.addAll(base.getResourceDirs());
+            mPaths.mOverlayPaths.addAll(base.getOverlayPaths());
+        }
+
         /**
          * Adds a non-APK path to the contents of {@link OverlayPaths#getOverlayPaths()}.
          */
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 6941857..2cb16d337b 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -10,7 +10,6 @@
 krishang@google.com
 riyaghai@google.com
 sahanas@google.com
-sergeynv@google.com
 shikhamalhotra@google.com
 shubhisaxena@google.com
 tylersaunders@google.com
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a2ce212..75fbff3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5922,7 +5922,7 @@
     <permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to collect usage infomation about brightness slider changes.
+    <!-- Allows an application to collect usage information about brightness slider changes.
          <p>Not for use by third-party applications.</p>
          @hide
          @SystemApi
diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml
index b8d93ac..509b988 100644
--- a/core/res/res/layout/app_perms_summary.xml
+++ b/core/res/res/layout/app_perms_summary.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- Describes permission item consisting of a group name and the list of permisisons under the group -->
+<!-- Describes permission item consisting of a group name and the list of permissions under the group -->
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
index 5aace81..e4cf7ac 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/TunerAdapterTest.java
@@ -286,7 +286,7 @@
         int scanStatus = mRadioTuner.scan(RadioTuner.DIRECTION_DOWN, /* skipSubChannel= */ false);
 
         verify(mTunerMock).seek(/* directionDown= */ true, /* skipSubChannel= */ false);
-        assertWithMessage("Status for scaning")
+        assertWithMessage("Status for scanning")
                 .that(scanStatus).isEqualTo(RadioManager.STATUS_OK);
         verify(mCallbackMock, timeout(CALLBACK_TIMEOUT_MS)).onProgramInfoChanged(FM_PROGRAM_INFO);
     }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 0806fa0..db95d7a 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -99,7 +99,7 @@
         }
     }
 
-    public int getSoftApInterations() {
+    public int getSoftApIterations() {
         return mSoftApIterations;
     }
 
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
index e6de597..9159a00 100644
--- a/graphics/java/android/view/PixelCopy.java
+++ b/graphics/java/android/view/PixelCopy.java
@@ -96,7 +96,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the SurfaceView's Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -117,7 +117,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the SurfaceView's Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -143,7 +143,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -164,7 +164,7 @@
      *
      * The contents of the source rect will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Surface will be used as the source of the copy.
      *
      * @param source The source from which to copy
@@ -201,7 +201,7 @@
      *
      * The contents of the source will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Window's Surface will be used as the source of the copy.
      *
      * Note: This is limited to being able to copy from Window's with a non-null
@@ -231,7 +231,7 @@
      *
      * The contents of the source rect will be scaled to fit exactly inside the bitmap.
      * The pixel format of the source buffer will be converted, as part of the copy,
-     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
+     * to fit the bitmap's {@link Bitmap.Config}. The most recently queued buffer
      * in the Window's Surface will be used as the source of the copy.
      *
      * Note: This is limited to being able to copy from Window's with a non-null
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index 2de8eef..ab5c54b 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -33,7 +33,7 @@
  * device at the boundary of the audio system.
  * In addition to base audio port attributes, the device descriptor contains:
  * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
- * - the device address (e.g MAC adddress for AD2P sink).
+ * - the device address (e.g MAC address for AD2P sink).
  * @see AudioPort
  * @hide
  */
diff --git a/media/java/android/media/AudioHalVersionInfo.java b/media/java/android/media/AudioHalVersionInfo.java
index 4cdfc51..2b6f72e 100644
--- a/media/java/android/media/AudioHalVersionInfo.java
+++ b/media/java/android/media/AudioHalVersionInfo.java
@@ -79,6 +79,9 @@
     /**
      * List of all valid Audio HAL versions. This list need to be in sync with sAudioHALVersions
      * defined in frameworks/av/media/libaudiohal/FactoryHal.cpp.
+     *
+     * Note: update {@link android.media.audio.cts.AudioHalVersionInfoTest} CTS accordingly if
+     * there is a change to supported versions.
      */
     public static final @NonNull List<AudioHalVersionInfo> VERSIONS =
             List.of(AIDL_1_0, HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0);
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 3252aad..1b29e83 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -526,7 +526,7 @@
     </string-array>
 
     <!-- USB configuration values for Developer Settings.
-         These are lists of USB functions passed to the USB Manager to change USB configuraton.
+         These are lists of USB functions passed to the USB Manager to change USB configuration.
          This can be overridden by devices with additional USB configurations.
          Do not translate. -->
     <string-array name="usb_configuration_values" translatable="false">
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 56576f1..407873e 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -420,3 +420,12 @@
     }
 }
 
+flag {
+   name: "get_connected_device_name_unsynchronized"
+   namespace: "systemui"
+   description: "Decide whether to fetch the connected bluetooth device name outside a synchronized block."
+   bug: "323995015"
+   metadata {
+       purpose: PURPOSE_BUGFIX
+     }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index fc2f6e9..c089092 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -35,6 +35,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.systemui.Flags;
 import com.android.systemui.bluetooth.BluetoothLogger;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -240,9 +241,21 @@
     @WorkerThread
     @Override
     public String getConnectedDeviceName() {
-        synchronized (mConnectedDevices) {
-            if (mConnectedDevices.size() == 1) {
-                return mConnectedDevices.get(0).getName();
+        if (Flags.getConnectedDeviceNameUnsynchronized()) {
+            CachedBluetoothDevice connectedDevice = null;
+            // Calling the getName() API for CachedBluetoothDevice outside the synchronized block
+            // so that the main thread is not blocked.
+            synchronized (mConnectedDevices) {
+                if (mConnectedDevices.size() == 1) {
+                    connectedDevice = mConnectedDevices.get(0);
+                }
+            }
+            return connectedDevice != null ? connectedDevice.getName() : null;
+        } else {
+            synchronized (mConnectedDevices) {
+                if (mConnectedDevices.size() == 1) {
+                    return mConnectedDevices.get(0).getName();
+                }
             }
         }
         return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
new file mode 100644
index 0000000..43450c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
@@ -0,0 +1,5 @@
+# Android TV Core Framework
+rgl@google.com
+valiiftime@google.com
+galinap@google.com
+robhor@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualLocationsService.kt b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualLocationsService.kt
index 1c17fc3..bb4a2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualLocationsService.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualLocationsService.kt
@@ -77,17 +77,17 @@
         controller.setSuggestionCardIds(storeLocations.toSet())
     }
 
-    private val binder: IWalletContextualLocationsService.Stub
-    = object : IWalletContextualLocationsService.Stub() {
-        override fun addWalletCardsUpdatedListener(listener: IWalletCardsUpdatedListener) {
-            addWalletCardsUpdatedListenerInternal(listener)
+    private val binder: IWalletContextualLocationsService.Stub =
+        object : IWalletContextualLocationsService.Stub() {
+            override fun addWalletCardsUpdatedListener(listener: IWalletCardsUpdatedListener) {
+                addWalletCardsUpdatedListenerInternal(listener)
+            }
+            override fun onWalletContextualLocationsStateUpdated(storeLocations: List<String>) {
+                onWalletContextualLocationsStateUpdatedInternal(storeLocations)
+            }
         }
-        override fun onWalletContextualLocationsStateUpdated(storeLocations: List<String>) {
-            onWalletContextualLocationsStateUpdatedInternal(storeLocations)
-        }
-    }
 
     companion object {
         private const val TAG = "WalletContextualLocationsService"
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt
index af1d788..e6b4d06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt
@@ -12,12 +12,9 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.TestCoroutineScope
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -41,11 +38,12 @@
     private lateinit var underTest: WalletContextualLocationsService
     private lateinit var testScope: TestScope
     private var listenerRegisteredCount: Int = 0
-    private val listener: IWalletCardsUpdatedListener.Stub = object : IWalletCardsUpdatedListener.Stub() {
-        override fun registerNewWalletCards(cards: List<WalletCard?>) {
-            listenerRegisteredCount++
+    private val listener: IWalletCardsUpdatedListener.Stub =
+        object : IWalletCardsUpdatedListener.Stub() {
+            override fun registerNewWalletCards(cards: List<WalletCard?>) {
+                listenerRegisteredCount++
+            }
         }
-    }
 
     @Before
     @kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,50 +58,56 @@
         featureFlags.set(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS, true)
         listenerRegisteredCount = 0
 
-        underTest = WalletContextualLocationsService(controller, featureFlags, testScope.backgroundScope)
+        underTest =
+            WalletContextualLocationsService(controller, featureFlags, testScope.backgroundScope)
     }
 
     @Test
     @kotlinx.coroutines.ExperimentalCoroutinesApi
-    fun addListener() = testScope.runTest {
-        underTest.addWalletCardsUpdatedListenerInternal(listener)
-        assertThat(listenerRegisteredCount).isEqualTo(1)
-  }
+    fun addListener() =
+        testScope.runTest {
+            underTest.addWalletCardsUpdatedListenerInternal(listener)
+            assertThat(listenerRegisteredCount).isEqualTo(1)
+        }
 
     @Test
     @kotlinx.coroutines.ExperimentalCoroutinesApi
-    fun addStoreLocations() = testScope.runTest {
-        underTest.onWalletContextualLocationsStateUpdatedInternal(ArrayList<String>())
-        verify(controller, times(1)).setSuggestionCardIds(anySet())
-    }
+    fun addStoreLocations() =
+        testScope.runTest {
+            underTest.onWalletContextualLocationsStateUpdatedInternal(ArrayList<String>())
+            verify(controller, times(1)).setSuggestionCardIds(anySet())
+        }
 
     @Test
     @kotlinx.coroutines.ExperimentalCoroutinesApi
-    fun updateListenerAndLocationsState() = testScope.runTest {
-        // binds to the service and adds a listener
-        val underTestStub = getInterface
-        underTestStub.addWalletCardsUpdatedListener(listener)
-        assertThat(listenerRegisteredCount).isEqualTo(1)
+    fun updateListenerAndLocationsState() =
+        testScope.runTest {
+            // binds to the service and adds a listener
+            val underTestStub = getInterface
+            underTestStub.addWalletCardsUpdatedListener(listener)
+            assertThat(listenerRegisteredCount).isEqualTo(1)
 
-        // sends a list of card IDs to the controller
-        underTestStub.onWalletContextualLocationsStateUpdated(ArrayList<String>())
-        verify(controller, times(1)).setSuggestionCardIds(anySet())
+            // sends a list of card IDs to the controller
+            underTestStub.onWalletContextualLocationsStateUpdated(ArrayList<String>())
+            verify(controller, times(1)).setSuggestionCardIds(anySet())
 
-        // adds another listener
-        fakeWalletCards.update{ updatedFakeWalletCards }
-        runCurrent()
-        assertThat(listenerRegisteredCount).isEqualTo(2)
+            // adds another listener
+            fakeWalletCards.update { updatedFakeWalletCards }
+            runCurrent()
+            assertThat(listenerRegisteredCount).isEqualTo(2)
 
-        // sends another list of card IDs to the controller
-        underTestStub.onWalletContextualLocationsStateUpdated(ArrayList<String>())
-        verify(controller, times(2)).setSuggestionCardIds(anySet())
-    }
+            // sends another list of card IDs to the controller
+            underTestStub.onWalletContextualLocationsStateUpdated(ArrayList<String>())
+            verify(controller, times(2)).setSuggestionCardIds(anySet())
+        }
 
     private val fakeWalletCards: MutableStateFlow<List<WalletCard>>
         get() {
             val intent = Intent(getContext(), WalletContextualLocationsService::class.java)
-            val pi: PendingIntent = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE)
-            val icon: Icon = Icon.createWithBitmap(Bitmap.createBitmap(70, 50, Bitmap.Config.ARGB_8888))
+            val pi: PendingIntent =
+                PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE)
+            val icon: Icon =
+                Icon.createWithBitmap(Bitmap.createBitmap(70, 50, Bitmap.Config.ARGB_8888))
             val walletCards: ArrayList<WalletCard> = ArrayList<WalletCard>()
             walletCards.add(WalletCard.Builder("card1", icon, "card", pi).build())
             walletCards.add(WalletCard.Builder("card2", icon, "card", pi).build())
@@ -113,8 +117,10 @@
     private val updatedFakeWalletCards: List<WalletCard>
         get() {
             val intent = Intent(getContext(), WalletContextualLocationsService::class.java)
-            val pi: PendingIntent = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE)
-            val icon: Icon = Icon.createWithBitmap(Bitmap.createBitmap(70, 50, Bitmap.Config.ARGB_8888))
+            val pi: PendingIntent =
+                PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE)
+            val icon: Icon =
+                Icon.createWithBitmap(Bitmap.createBitmap(70, 50, Bitmap.Config.ARGB_8888))
             val walletCards: ArrayList<WalletCard> = ArrayList<WalletCard>()
             walletCards.add(WalletCard.Builder("card3", icon, "card", pi).build())
             return walletCards
@@ -125,4 +131,4 @@
             val intent = Intent()
             return IWalletContextualLocationsService.Stub.asInterface(underTest.onBind(intent))
         }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3507d2d..6936ae0 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6309,6 +6309,10 @@
             Objects.requireNonNull(user);
 
             verifyPrivilegedListener(token, user, false);
+
+            final NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
+                    pkg, getUidForPackageAndUser(pkg, user), channel.getId(), true);
+            verifyPrivilegedListenerUriPermission(Binder.getCallingUid(), channel, originalChannel);
             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
         }
 
@@ -6406,6 +6410,24 @@
             }
         }
 
+        private void verifyPrivilegedListenerUriPermission(int sourceUid,
+                @NonNull NotificationChannel updateChannel,
+                @Nullable NotificationChannel originalChannel) {
+            // Check that the NLS has the required permissions to access the channel
+            final Uri soundUri = updateChannel.getSound();
+            final Uri originalSoundUri =
+                    (originalChannel != null) ? originalChannel.getSound() : null;
+            if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) {
+                Binder.withCleanCallingIdentity(() -> {
+                    mUgmInternal.checkGrantUriPermission(sourceUid, null,
+                            ContentProvider.getUriWithoutUserId(soundUri),
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                            ContentProvider.getUserIdFromUri(soundUri,
+                            UserHandle.getUserId(sourceUid)));
+                });
+            }
+        }
+
         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
             int uid = INVALID_UID;
             final long identity = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index b9464d9..8729522 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -362,7 +362,7 @@
                 defaultPackages.add(packageName);
             }
         }
-        return defaultPackages.toArray(new String[defaultPackages.size()]);
+        return defaultPackages.toArray(new String[0]);
     }
 
     private final class OverlayManagerPackageMonitor extends PackageMonitor {
@@ -1160,7 +1160,7 @@
         // state may lead to contradictions within OMS. Better then to lag
         // behind until all pending intents have been processed.
         private final ArrayMap<String, PackageStateUsers> mCache = new ArrayMap<>();
-        private final Set<Integer> mInitializedUsers = new ArraySet<>();
+        private final ArraySet<Integer> mInitializedUsers = new ArraySet<>();
 
         PackageManagerHelperImpl(Context context) {
             mContext = context;
@@ -1176,8 +1176,7 @@
          */
         @NonNull
         public ArrayMap<String, PackageState> initializeForUser(final int userId) {
-            if (!mInitializedUsers.contains(userId)) {
-                mInitializedUsers.add(userId);
+            if (mInitializedUsers.add(userId)) {
                 mPackageManagerInternal.forEachPackageState((packageState -> {
                     if (packageState.getPkg() != null
                             && packageState.getUserStateOrDefault(userId).isInstalled()) {
@@ -1545,8 +1544,7 @@
                 final OverlayPaths frameworkOverlays =
                         mImpl.getEnabledOverlayPaths("android", userId, false);
                 for (final String targetPackageName : targetPackageNames) {
-                    final OverlayPaths.Builder list = new OverlayPaths.Builder();
-                    list.addAll(frameworkOverlays);
+                    final var list = new OverlayPaths.Builder(frameworkOverlays);
                     if (!"android".equals(targetPackageName)) {
                         list.addAll(mImpl.getEnabledOverlayPaths(targetPackageName, userId, true));
                     }
@@ -1558,17 +1556,21 @@
             final HashSet<String> invalidPackages = new HashSet<>();
             pm.setEnabledOverlayPackages(userId, pendingChanges, updatedPackages, invalidPackages);
 
-            for (final String targetPackageName : targetPackageNames) {
-                if (DEBUG) {
-                    Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
-                            + pendingChanges.get(targetPackageName)
-                            + "] userId=" + userId);
-                }
+            if (DEBUG || !invalidPackages.isEmpty()) {
+                for (final String targetPackageName : targetPackageNames) {
+                    if (DEBUG) {
+                        Slog.d(TAG,
+                                "-> Updating overlay: target=" + targetPackageName + " overlays=["
+                                        + pendingChanges.get(targetPackageName)
+                                        + "] userId=" + userId);
+                    }
 
-                if (invalidPackages.contains(targetPackageName)) {
-                    Slog.e(TAG, TextUtils.formatSimple(
-                            "Failed to change enabled overlays for %s user %d", targetPackageName,
-                            userId));
+                    if (invalidPackages.contains(targetPackageName)) {
+                        Slog.e(TAG, TextUtils.formatSimple(
+                                "Failed to change enabled overlays for %s user %d",
+                                targetPackageName,
+                                userId));
+                    }
                 }
             }
             return new ArrayList<>(updatedPackages);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 972c78d..c1b6ccc 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -772,24 +772,20 @@
 
     OverlayPaths getEnabledOverlayPaths(@NonNull final String targetPackageName,
             final int userId, boolean includeImmutableOverlays) {
-        final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
-                userId);
-        final OverlayPaths.Builder paths = new OverlayPaths.Builder();
-        final int n = overlays.size();
-        for (int i = 0; i < n; i++) {
-            final OverlayInfo oi = overlays.get(i);
+        final var paths = new OverlayPaths.Builder();
+        mSettings.forEachMatching(userId, null, targetPackageName, oi -> {
             if (!oi.isEnabled()) {
-                continue;
+                return;
             }
             if (!includeImmutableOverlays && !oi.isMutable) {
-                continue;
+                return;
             }
             if (oi.isFabricated()) {
                 paths.addNonApkPath(oi.baseCodePath);
             } else {
                 paths.addApkPath(oi.baseCodePath);
             }
-        }
+        });
         return paths.build();
     }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index eae614a..b8b49f3e 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -47,6 +47,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -182,6 +183,23 @@
         return CollectionUtils.map(items, SettingsItem::getOverlayInfo);
     }
 
+    void forEachMatching(int userId, String overlayName, String targetPackageName,
+            @NonNull Consumer<OverlayInfo> consumer) {
+        for (int i = 0, n = mItems.size(); i < n; i++) {
+            final SettingsItem item = mItems.get(i);
+            if (item.getUserId() != userId) {
+                continue;
+            }
+            if (overlayName != null && !item.mOverlay.getPackageName().equals(overlayName)) {
+                continue;
+            }
+            if (targetPackageName != null && !item.mTargetPackageName.equals(targetPackageName)) {
+                continue;
+            }
+            consumer.accept(item.getOverlayInfo());
+        }
+    }
+
     ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
         final List<SettingsItem> items = selectWhereUser(userId);
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS
index c0f0ce0..b363f54 100644
--- a/services/tests/mockingservicestests/src/com/android/server/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS
@@ -1,3 +1,4 @@
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
 per-file *AppStateTracker* = file:/apex/jobscheduler/OWNERS
 per-file *DeviceIdleController* = file:/apex/jobscheduler/OWNERS
+per-file SensitiveContentProtectionManagerServiceTest.java = file:/core/java/android/permission/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 2f740ea..cb9490e 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4002,6 +4002,69 @@
     }
 
     @Test
+    public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
+            throws Exception {
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mCompanionMgr.getAssociations(PKG, mUserId))
+                .thenReturn(singletonList(mock(AssociationInfo.class)));
+        when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
+                eq(mTestNotificationChannel.getId()), anyBoolean()))
+                .thenReturn(mTestNotificationChannel);
+
+        final Uri soundUri = Uri.parse("content://media/test/sound/uri");
+        final NotificationChannel updatedNotificationChannel = new NotificationChannel(
+                TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
+        updatedNotificationChannel.setSound(soundUri,
+                updatedNotificationChannel.getAudioAttributes());
+
+        doThrow(new SecurityException("no access")).when(mUgmInternal)
+                .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
+                anyInt(), eq(Process.myUserHandle().getIdentifier()));
+
+        assertThrows(SecurityException.class,
+                () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, PKG,
+                Process.myUserHandle(), updatedNotificationChannel));
+
+        verify(mPreferencesHelper, never()).updateNotificationChannel(
+                anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
+
+        verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
+                eq(Process.myUserHandle()), eq(mTestNotificationChannel),
+                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
+    }
+
+    @Test
+    public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
+            throws Exception {
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mCompanionMgr.getAssociations(PKG, mUserId))
+                .thenReturn(singletonList(mock(AssociationInfo.class)));
+        when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
+                eq(mTestNotificationChannel.getId()), anyBoolean()))
+                .thenReturn(mTestNotificationChannel);
+
+        final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+        final NotificationChannel updatedNotificationChannel = new NotificationChannel(
+                TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
+        updatedNotificationChannel.setSound(soundUri,
+                updatedNotificationChannel.getAudioAttributes());
+
+        doThrow(new SecurityException("no access")).when(mUgmInternal)
+                .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri),
+                    anyInt(), eq(Process.myUserHandle().getIdentifier()));
+
+        mBinderService.updateNotificationChannelFromPrivilegedListener(
+                null, PKG, Process.myUserHandle(), updatedNotificationChannel);
+
+        verify(mPreferencesHelper, times(1)).updateNotificationChannel(
+                anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
+
+        verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
+                eq(Process.myUserHandle()), eq(mTestNotificationChannel),
+                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
+    }
+
+    @Test
     public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
         when(mCompanionMgr.getAssociations(PKG, mUserId))