Merge "[Media SASS] Use the device's address to fetch the full MediaDevice information so that we display the correct icon." into tm-dev am: 0db54b283e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17297743 Change-Id: If7d41030974b5088e213339f40b76a001cd1149b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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() {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
val deviceCallback = captureCallback()
|
||||
// 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)
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user