Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd431cc6 authored by Caitlin Cassidy's avatar Caitlin Cassidy Committed by Automerger Merge Worker
Browse files

Merge "[Media SASS] Use the device's address to fetch the full MediaDevice...

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: 0db54b28

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17297743



Change-Id: I35ce210688e0bb93801185aef1eaa5b0a6af6549
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 77d2439e 0db54b28
Loading
Loading
Loading
Loading
+34 −8
Original line number Diff line number Diff line
@@ -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.
         */
        default void onAboutToConnectDeviceChanged(
                @Nullable String deviceName,
         * 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 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() {}
    }

    /**
+37 −11
Original line number Diff line number Diff line
@@ -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
            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
)
+6 −4
Original line number Diff line number Diff line
@@ -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()
            )
        }
    }
+46 −8
Original line number Diff line number Diff line
@@ -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)
+15 −10
Original line number Diff line number Diff line
@@ -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(),