summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt25
5 files changed, 138 insertions, 41 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index c2e36b79b753..e1a2e8daf971 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -28,6 +28,7 @@ import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -239,13 +240,24 @@ public class LocalMediaManager implements BluetoothCallback {
/**
* Dispatch a change in the about-to-connect device. See
- * {@link DeviceCallback#onAboutToConnectDeviceChanged} for more information.
+ * {@link DeviceCallback#onAboutToConnectDeviceAdded} for more information.
*/
- public void dispatchAboutToConnectDeviceChanged(
- @Nullable String deviceName,
+ public void dispatchAboutToConnectDeviceAdded(
+ @NonNull String deviceAddress,
+ @NonNull String deviceName,
@Nullable Drawable deviceIcon) {
for (DeviceCallback callback : getCallbacks()) {
- callback.onAboutToConnectDeviceChanged(deviceName, deviceIcon);
+ callback.onAboutToConnectDeviceAdded(deviceAddress, deviceName, deviceIcon);
+ }
+ }
+
+ /**
+ * Dispatch a change in the about-to-connect device. See
+ * {@link DeviceCallback#onAboutToConnectDeviceRemoved} for more information.
+ */
+ public void dispatchAboutToConnectDeviceRemoved() {
+ for (DeviceCallback callback : getCallbacks()) {
+ callback.onAboutToConnectDeviceRemoved();
}
}
@@ -705,13 +717,27 @@ public class LocalMediaManager implements BluetoothCallback {
* connect imminently and should be displayed as the current device in the media player.
* See [AudioManager.muteAwaitConnection] for more details.
*
- * @param deviceName the name of the device (displayed to the user).
- * @param deviceIcon the icon that should be used with the device.
+ * The information in the most recent callback should override information from any previous
+ * callbacks.
+ *
+ * @param deviceAddress the address of the device. {@see AudioDeviceAttributes.address}.
+ * If present, we'll use this address to fetch the full information
+ * about the device (if we can find that information).
+ * @param deviceName the name of the device (displayed to the user). Used as a backup in
+ * case using deviceAddress doesn't work.
+ * @param deviceIcon the icon that should be used with the device. Used as a backup in case
+ * using deviceAddress doesn't work.
*/
- default void onAboutToConnectDeviceChanged(
- @Nullable String deviceName,
+ default void onAboutToConnectDeviceAdded(
+ @NonNull String deviceAddress,
+ @NonNull String deviceName,
@Nullable Drawable deviceIcon
) {}
+
+ /**
+ * Callback for notifying that we no longer have an about-to-connect device.
+ */
+ default void onAboutToConnectDeviceRemoved() {}
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 824a6fd9d96e..d6231911244f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -164,7 +164,7 @@ class MediaDeviceManager @Inject constructor(
}
// A device that is not yet connected but is expected to connect imminently. Because it's
// expected to connect imminently, it should be displayed as the current device.
- private var aboutToConnectDeviceOverride: MediaDeviceData? = null
+ private var aboutToConnectDeviceOverride: AboutToConnectDevice? = null
@AnyThread
fun start() = bgExecutor.execute {
@@ -222,22 +222,34 @@ class MediaDeviceManager @Inject constructor(
}
}
- override fun onAboutToConnectDeviceChanged(deviceName: String?, deviceIcon: Drawable?) {
- aboutToConnectDeviceOverride = if (deviceName == null || deviceIcon == null) {
- null
- } else {
- MediaDeviceData(enabled = true, deviceIcon, deviceName)
- }
+ override fun onAboutToConnectDeviceAdded(
+ deviceAddress: String,
+ deviceName: String,
+ deviceIcon: Drawable?
+ ) {
+ aboutToConnectDeviceOverride = AboutToConnectDevice(
+ fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress),
+ backupMediaDeviceData = MediaDeviceData(enabled = true, deviceIcon, deviceName)
+ )
+ updateCurrent()
+ }
+
+ override fun onAboutToConnectDeviceRemoved() {
+ aboutToConnectDeviceOverride = null
updateCurrent()
}
@WorkerThread
private fun updateCurrent() {
- if (aboutToConnectDeviceOverride != null) {
- current = aboutToConnectDeviceOverride
- return
+ val aboutToConnect = aboutToConnectDeviceOverride
+ if (aboutToConnect != null &&
+ aboutToConnect.fullMediaDevice == null &&
+ aboutToConnect.backupMediaDeviceData != null) {
+ // Only use [backupMediaDeviceData] when we don't have [fullMediaDevice].
+ current = aboutToConnect.backupMediaDeviceData
+ return
}
- val device = localMediaManager.currentConnectedDevice
+ val device = aboutToConnect?.fullMediaDevice ?: localMediaManager.currentConnectedDevice
val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
// If we have a controller but get a null route, then don't trust the device
@@ -247,3 +259,17 @@ class MediaDeviceManager @Inject constructor(
}
}
}
+
+/**
+ * A class storing information for the about-to-connect device. See
+ * [LocalMediaManager.DeviceCallback.onAboutToConnectDeviceAdded] for more information.
+ *
+ * @property fullMediaDevice a full-fledged [MediaDevice] object representing the device. If
+ * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData].
+ * @property backupMediaDeviceData a backup [MediaDeviceData] object containing the minimum
+ * information required to display the device. Only use if [fullMediaDevice] is null.
+ */
+private data class AboutToConnectDevice(
+ val fullMediaDevice: MediaDevice? = null,
+ val backupMediaDeviceData: MediaDeviceData? = null
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
index 22bc5572f5a5..2783532aff97 100644
--- a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
@@ -52,7 +52,9 @@ class MediaMuteAwaitConnectionManager constructor(
// There should only be one device that's mutedUntilConnection at a time, so we can
// safely override any previous value.
currentMutedDevice = device
- localMediaManager.dispatchAboutToConnectDeviceChanged(device.name, device.getIcon())
+ localMediaManager.dispatchAboutToConnectDeviceAdded(
+ device.address, device.name, device.getIcon()
+ )
}
}
@@ -63,7 +65,7 @@ class MediaMuteAwaitConnectionManager constructor(
) {
if (currentMutedDevice == device && USAGE_MEDIA in mutedUsages) {
currentMutedDevice = null
- localMediaManager.dispatchAboutToConnectDeviceChanged(null, null)
+ localMediaManager.dispatchAboutToConnectDeviceRemoved()
}
}
}
@@ -76,8 +78,8 @@ class MediaMuteAwaitConnectionManager constructor(
val currentDevice = audioManager.mutingExpectedDevice
if (currentDevice != null) {
currentMutedDevice = currentDevice
- localMediaManager.dispatchAboutToConnectDeviceChanged(
- currentDevice.name, currentDevice.getIcon()
+ localMediaManager.dispatchAboutToConnectDeviceAdded(
+ currentDevice.address, currentDevice.name, currentDevice.getIcon()
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index e6f48ecd37de..10eeb11faa05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -265,20 +265,58 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
}
@Test
- fun onAboutToConnectDeviceChangedWithNonNullParams() {
+ fun onAboutToConnectDeviceAdded_findsDeviceInfoFromAddress() {
manager.onMediaDataLoaded(KEY, null, mediaData)
// Run and reset the executors and listeners so we only focus on new events.
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
reset(listener)
+ // Ensure we'll get device info when using the address
+ val fullMediaDevice = mock(MediaDevice::class.java)
+ val address = "fakeAddress"
+ val nameFromDevice = "nameFromDevice"
+ val iconFromDevice = mock(Drawable::class.java)
+ whenever(lmm.getMediaDeviceById(eq(address))).thenReturn(fullMediaDevice)
+ whenever(fullMediaDevice.name).thenReturn(nameFromDevice)
+ whenever(fullMediaDevice.iconWithoutBackground).thenReturn(iconFromDevice)
+
+ // WHEN the about-to-connect device changes to non-null
val deviceCallback = captureCallback()
+ val nameFromParam = "nameFromParam"
+ val iconFromParam = mock(Drawable::class.java)
+ deviceCallback.onAboutToConnectDeviceAdded(address, nameFromParam, iconFromParam)
+ assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
+
+ // THEN the about-to-connect device based on the address is returned
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(nameFromDevice)
+ assertThat(data.name).isNotEqualTo(nameFromParam)
+ assertThat(data.icon).isEqualTo(iconFromDevice)
+ assertThat(data.icon).isNotEqualTo(iconFromParam)
+ }
+
+ @Test
+ fun onAboutToConnectDeviceAdded_cantFindDeviceInfoFromAddress() {
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ // Run and reset the executors and listeners so we only focus on new events.
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(listener)
+
+ // Ensure we can't get device info based on the address
+ val address = "fakeAddress"
+ whenever(lmm.getMediaDeviceById(eq(address))).thenReturn(null)
+
// WHEN the about-to-connect device changes to non-null
+ val deviceCallback = captureCallback()
val name = "AboutToConnectDeviceName"
val mockIcon = mock(Drawable::class.java)
- deviceCallback.onAboutToConnectDeviceChanged(name, mockIcon)
+ deviceCallback.onAboutToConnectDeviceAdded(address, name, mockIcon)
assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
- // THEN the about-to-connect device is returned
+
+ // THEN the about-to-connect device based on the parameters is returned
val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(name)
@@ -286,21 +324,21 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
}
@Test
- fun onAboutToConnectDeviceChangedWithNullParams() {
+ fun onAboutToConnectDeviceAddedThenRemoved_usesNormalDevice() {
manager.onMediaDataLoaded(KEY, null, mediaData)
fakeBgExecutor.runAllReady()
val deviceCallback = captureCallback()
// First set a non-null about-to-connect device
- deviceCallback.onAboutToConnectDeviceChanged(
- "AboutToConnectDeviceName", mock(Drawable::class.java)
+ deviceCallback.onAboutToConnectDeviceAdded(
+ "fakeAddress", "AboutToConnectDeviceName", mock(Drawable::class.java)
)
// Run and reset the executors and listeners so we only focus on new events.
fakeBgExecutor.runAllReady()
fakeFgExecutor.runAllReady()
reset(listener)
- // WHEN the about-to-connect device changes to null
- deviceCallback.onAboutToConnectDeviceChanged(null, null)
+ // WHEN hasDevice switches to false
+ deviceCallback.onAboutToConnectDeviceRemoved()
assertThat(fakeFgExecutor.runAllReady()).isEqualTo(1)
// THEN the normal device is returned
val data = captureDeviceData(KEY)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
index 88c451499d21..27c039dcf29c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
@@ -24,7 +24,7 @@ import android.media.AudioDeviceAttributes
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.media.AudioManager.MuteAwaitConnectionCallback.EVENT_CONNECTION
-import android.test.suitebuilder.annotation.SmallTest
+import androidx.test.filters.SmallTest
import com.android.settingslib.media.DeviceIconUtil
import com.android.settingslib.media.LocalMediaManager
import com.android.systemui.R
@@ -95,7 +95,7 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitConnectionManager.startListening()
- verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any())
}
@Test
@@ -104,7 +104,9 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitConnectionManager.startListening()
- verify(localMediaManager).dispatchAboutToConnectDeviceChanged(eq(DEVICE_NAME), eq(icon))
+ verify(localMediaManager).dispatchAboutToConnectDeviceAdded(
+ eq(DEVICE_ADDRESS), eq(DEVICE_NAME), eq(icon)
+ )
}
@Test
@@ -114,7 +116,7 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_UNKNOWN))
- verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any())
}
@Test
@@ -125,7 +127,9 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
- verify(localMediaManager).dispatchAboutToConnectDeviceChanged(eq(DEVICE_NAME), eq(icon))
+ verify(localMediaManager).dispatchAboutToConnectDeviceAdded(
+ eq(DEVICE_ADDRESS), eq(DEVICE_NAME), eq(icon)
+ )
}
@Test
@@ -135,7 +139,7 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA))
- verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any())
}
@Test
@@ -155,7 +159,7 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
)
muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, otherDevice, intArrayOf(USAGE_MEDIA))
- verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any())
}
@Test
@@ -167,7 +171,7 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_UNKNOWN))
- verify(localMediaManager, never()).dispatchAboutToConnectDeviceChanged(any(), any())
+ verify(localMediaManager, never()).dispatchAboutToConnectDeviceAdded(any(), any(), any())
}
@Test
@@ -179,7 +183,7 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA))
- verify(localMediaManager).dispatchAboutToConnectDeviceChanged(eq(null), eq(null))
+ verify(localMediaManager).dispatchAboutToConnectDeviceRemoved()
}
private fun getMuteAwaitListener(): AudioManager.MuteAwaitConnectionCallback {
@@ -191,11 +195,12 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
}
}
+private const val DEVICE_ADDRESS = "DeviceAddress"
private const val DEVICE_NAME = "DeviceName"
private val DEVICE = AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_USB_HEADSET,
- "address",
+ DEVICE_ADDRESS,
DEVICE_NAME,
listOf(),
listOf(),