Merge changes I3d1952ae,I42f5d4b1 into tm-dev

* changes:
  [Media] Add logging for NearbyMediaDevicesManager.
  [Media] Add logging to MediaMuteAwaitConnectionManager.
This commit is contained in:
TreeHugger Robot
2022-04-19 03:26:54 +00:00
committed by Android (Google) Code Review
10 changed files with 353 additions and 14 deletions

View File

@@ -176,6 +176,29 @@ public class LogModule {
return factory.create("MediaTttReceiver", 20);
}
/**
* Provides a logging buffer for logs related to the media mute-await connections. See
* {@link com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager}.
*/
@Provides
@SysUISingleton
@MediaMuteAwaitLog
public static LogBuffer provideMediaMuteAwaitLogBuffer(LogBufferFactory factory) {
return factory.create("MediaMuteAwaitLog", 20);
}
/**
* Provides a logging buffer for logs related to the media mute-await connections. See
* {@link com.android.systemui.media.nearby.NearbyMediaDevicesManager}.
*/
@Provides
@SysUISingleton
@NearbyMediaDevicesLog
public static LogBuffer provideNearbyMediaDevicesLogBuffer(LogBufferFactory factory) {
return factory.create("NearbyMediaDevicesLog", 20);
}
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2022 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.
*/
package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
/**
* A {@link LogBuffer} for
* {@link com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager}.
*/
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface MediaMuteAwaitLog {
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2022 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.
*/
package com.android.systemui.log.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
/** A {@link LogBuffer} for {@link com.android.systemui.media.nearby.NearbyMediaDevicesManager}. */
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface NearbyMediaDevicesLog {
}

View File

@@ -33,14 +33,13 @@ import java.util.concurrent.Executor
* will be notified.
*
* See [AudioManager.muteAwaitConnection] and b/206614671 for more details.
*
* TODO(b/206614671): Add logging.
*/
class MediaMuteAwaitConnectionManager constructor(
@Main private val mainExecutor: Executor,
private val localMediaManager: LocalMediaManager,
private val context: Context,
private val deviceIconUtil: DeviceIconUtil
private val deviceIconUtil: DeviceIconUtil,
private val logger: MediaMuteAwaitLogger
) {
var currentMutedDevice: AudioDeviceAttributes? = null
@@ -48,7 +47,8 @@ class MediaMuteAwaitConnectionManager constructor(
val muteAwaitConnectionChangeListener = object : AudioManager.MuteAwaitConnectionCallback() {
override fun onMutedUntilConnection(device: AudioDeviceAttributes, mutedUsages: IntArray) {
if (USAGE_MEDIA in mutedUsages) {
logger.logMutedDeviceAdded(device.address, device.name, mutedUsages.hasMedia())
if (mutedUsages.hasMedia()) {
// There should only be one device that's mutedUntilConnection at a time, so we can
// safely override any previous value.
currentMutedDevice = device
@@ -63,7 +63,11 @@ class MediaMuteAwaitConnectionManager constructor(
device: AudioDeviceAttributes,
mutedUsages: IntArray
) {
if (currentMutedDevice == device && USAGE_MEDIA in mutedUsages) {
val isMostRecentDevice = currentMutedDevice == device
logger.logMutedDeviceRemoved(
device.address, device.name, mutedUsages.hasMedia(), isMostRecentDevice
)
if (isMostRecentDevice && mutedUsages.hasMedia()) {
currentMutedDevice = null
localMediaManager.dispatchAboutToConnectDeviceRemoved()
}
@@ -92,4 +96,6 @@ class MediaMuteAwaitConnectionManager constructor(
private fun AudioDeviceAttributes.getIcon(): Drawable {
return deviceIconUtil.getIconFromAudioDeviceType(this.type, context)
}
private fun IntArray.hasMedia() = USAGE_MEDIA in this
}

View File

@@ -30,6 +30,7 @@ import javax.inject.Inject
class MediaMuteAwaitConnectionManagerFactory @Inject constructor(
private val mediaFlags: MediaFlags,
private val context: Context,
private val logger: MediaMuteAwaitLogger,
@Main private val mainExecutor: Executor
) {
private val deviceIconUtil = DeviceIconUtil()
@@ -40,7 +41,7 @@ class MediaMuteAwaitConnectionManagerFactory @Inject constructor(
return null
}
return MediaMuteAwaitConnectionManager(
mainExecutor, localMediaManager, context, deviceIconUtil
mainExecutor, localMediaManager, context, deviceIconUtil, logger
)
}
}

View File

@@ -0,0 +1,51 @@
package com.android.systemui.media.muteawait
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.MediaMuteAwaitLog
import javax.inject.Inject
/** Log messages for [MediaMuteAwaitConnectionManager]. */
@SysUISingleton
class MediaMuteAwaitLogger @Inject constructor(
@MediaMuteAwaitLog private val buffer: LogBuffer
) {
/** Logs that a muted device has been newly added. */
fun logMutedDeviceAdded(deviceAddress: String, deviceName: String, hasMediaUsage: Boolean) =
buffer.log(
TAG,
LogLevel.DEBUG,
{
str1 = deviceAddress
str2 = deviceName
bool1 = hasMediaUsage
},
{
"Muted device added: address=$str1 name=$str2 hasMediaUsage=$bool1"
}
)
/** Logs that a muted device has been removed. */
fun logMutedDeviceRemoved(
deviceAddress: String,
deviceName: String,
hasMediaUsage: Boolean,
isMostRecentDevice: Boolean
) = buffer.log(
TAG,
LogLevel.DEBUG,
{
str1 = deviceAddress
str2 = deviceName
bool1 = hasMediaUsage
bool2 = isMostRecentDevice
},
{
"Muted device removed: " +
"address=$str1 name=$str2 hasMediaUsage=$bool1 isMostRecentDevice=$bool2"
}
)
}
private const val TAG = "MediaMuteAwait"

View File

@@ -0,0 +1,51 @@
package com.android.systemui.media.nearby
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.NearbyMediaDevicesLog
import javax.inject.Inject
/** Log messages for [NearbyMediaDevicesManager]. */
@SysUISingleton
class NearbyMediaDevicesLogger @Inject constructor(
@NearbyMediaDevicesLog private val buffer: LogBuffer
) {
/**
* Log that a new provider was registered.
*
* @param numProviders the total number of providers that are currently registered.
*/
fun logProviderRegistered(numProviders: Int) = buffer.log(
TAG,
LogLevel.DEBUG,
{ int1 = numProviders },
{ "Provider registered; total providers = $int1" }
)
/**
* Log that a new provider was unregistered.
*
* @param numProviders the total number of providers that are currently registered.
*/
fun logProviderUnregistered(numProviders: Int) = buffer.log(
TAG,
LogLevel.DEBUG,
{ int1 = numProviders },
{ "Provider unregistered; total providers = $int1" }
)
/**
* Log that a provider's binder has died.
*
* @param numProviders the total number of providers that are currently registered.
*/
fun logProviderBinderDied(numProviders: Int) = buffer.log(
TAG,
LogLevel.DEBUG,
{ int1 = numProviders },
{ "Provider binder died; total providers = $int1" }
)
}
private const val TAG = "NearbyMediaDevices"

View File

@@ -27,12 +27,11 @@ import javax.inject.Inject
* A service that acts as a bridge between (1) external clients that have data on nearby devices
* that are able to play media and (2) internal clients (like media Output Switcher) that need data
* on these nearby devices.
*
* TODO(b/216313420): Add logging to this class.
*/
@SysUISingleton
class NearbyMediaDevicesManager @Inject constructor(
commandQueue: CommandQueue
commandQueue: CommandQueue,
private val logger: NearbyMediaDevicesLogger
) {
private var providers: MutableList<INearbyMediaDevicesProvider> = mutableListOf()
private var activeCallbacks: MutableList<INearbyMediaDevicesUpdateCallback> = mutableListOf()
@@ -46,13 +45,17 @@ class NearbyMediaDevicesManager @Inject constructor(
newProvider.registerNearbyDevicesCallback(it)
}
providers.add(newProvider)
logger.logProviderRegistered(providers.size)
newProvider.asBinder().linkToDeath(deathRecipient, /* flags= */ 0)
}
override fun unregisterNearbyMediaDevicesProvider(
newProvider: INearbyMediaDevicesProvider
) {
providers.remove(newProvider)
val isRemoved = providers.remove(newProvider)
if (isRemoved) {
logger.logProviderUnregistered(providers.size)
}
}
}
@@ -99,6 +102,7 @@ class NearbyMediaDevicesManager @Inject constructor(
for (i in providers.size - 1 downTo 0) {
if (providers[i].asBinder() == who) {
providers.removeAt(i)
logger.logProviderBinderDied(providers.size)
break
}
}

View File

@@ -53,6 +53,8 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
private lateinit var deviceIconUtil: DeviceIconUtil
@Mock
private lateinit var localMediaManager: LocalMediaManager
@Mock
private lateinit var logger: MediaMuteAwaitLogger
private lateinit var icon: Drawable
@Before
@@ -66,7 +68,8 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
FakeExecutor(FakeSystemClock()),
localMediaManager,
context,
deviceIconUtil
deviceIconUtil,
logger
)
}
@@ -186,6 +189,39 @@ class MediaMuteAwaitConnectionManagerTest : SysuiTestCase() {
verify(localMediaManager).dispatchAboutToConnectDeviceRemoved()
}
@Test
fun onMutedUntilConnection_isLogged() {
muteAwaitConnectionManager.startListening()
getMuteAwaitListener().onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
verify(logger).logMutedDeviceAdded(DEVICE_ADDRESS, DEVICE_NAME, hasMediaUsage = true)
}
@Test
fun onUnmutedEvent_notMostRecentDevice_isLogged() {
muteAwaitConnectionManager.startListening()
getMuteAwaitListener().onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA))
verify(logger).logMutedDeviceRemoved(
DEVICE_ADDRESS, DEVICE_NAME, hasMediaUsage = true, isMostRecentDevice = false
)
}
@Test
fun onUnmutedEvent_isMostRecentDevice_isLogged() {
muteAwaitConnectionManager.startListening()
val muteAwaitListener = getMuteAwaitListener()
muteAwaitListener.onMutedUntilConnection(DEVICE, intArrayOf(USAGE_MEDIA))
muteAwaitListener.onUnmutedEvent(EVENT_CONNECTION, DEVICE, intArrayOf(USAGE_MEDIA))
verify(logger).logMutedDeviceRemoved(
DEVICE_ADDRESS, DEVICE_NAME, hasMediaUsage = true, isMostRecentDevice = true
)
}
private fun getMuteAwaitListener(): AudioManager.MuteAwaitConnectionCallback {
val listenerCaptor = ArgumentCaptor.forClass(
AudioManager.MuteAwaitConnectionCallback::class.java

View File

@@ -5,13 +5,18 @@ import android.media.INearbyMediaDevicesUpdateCallback
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import android.media.NearbyDevice
import android.os.IBinder
import com.android.systemui.statusbar.CommandQueue
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
@@ -19,16 +24,18 @@ class NearbyMediaDevicesManagerTest : SysuiTestCase() {
private lateinit var manager: NearbyMediaDevicesManager
@Mock
private lateinit var logger: NearbyMediaDevicesLogger
@Mock
private lateinit var commandQueue: CommandQueue
private lateinit var commandQueueCallbacks: CommandQueue.Callbacks
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
manager = NearbyMediaDevicesManager(commandQueue)
manager = NearbyMediaDevicesManager(commandQueue, logger)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
Mockito.verify(commandQueue).addCallback(callbackCaptor.capture())
verify(commandQueue).addCallback(callbackCaptor.capture())
commandQueueCallbacks = callbackCaptor.value!!
}
@@ -128,9 +135,92 @@ class NearbyMediaDevicesManagerTest : SysuiTestCase() {
assertThat(provider2.lastRegisteredCallback).isEqualTo(callback)
}
@Test
fun providerUnregistered_doesNotReceiveNewCallback() {
val provider = TestProvider()
commandQueueCallbacks.registerNearbyMediaDevicesProvider(provider)
commandQueueCallbacks.unregisterNearbyMediaDevicesProvider(provider)
val callback = object : INearbyMediaDevicesUpdateCallback.Stub() {
override fun onDevicesUpdated(nearbyDevices: List<NearbyDevice>) {}
}
manager.registerNearbyDevicesCallback(callback)
assertThat(provider.lastRegisteredCallback).isEqualTo(null)
}
@Test
fun providerRegistered_isLogged() {
commandQueueCallbacks.registerNearbyMediaDevicesProvider(TestProvider())
verify(logger).logProviderRegistered(numProviders = 1)
}
@Test
fun providerRegisteredTwice_onlyLoggedOnce() {
val provider = TestProvider()
commandQueueCallbacks.registerNearbyMediaDevicesProvider(provider)
commandQueueCallbacks.registerNearbyMediaDevicesProvider(provider)
verify(logger, times(1)).logProviderRegistered(numProviders = 1)
}
@Test
fun multipleProvidersRegistered_isLogged() {
commandQueueCallbacks.registerNearbyMediaDevicesProvider(TestProvider())
commandQueueCallbacks.registerNearbyMediaDevicesProvider(TestProvider())
reset(logger)
commandQueueCallbacks.registerNearbyMediaDevicesProvider(TestProvider())
verify(logger).logProviderRegistered(numProviders = 3)
}
@Test
fun providerUnregistered_isLogged() {
val provider = TestProvider()
commandQueueCallbacks.registerNearbyMediaDevicesProvider(provider)
commandQueueCallbacks.unregisterNearbyMediaDevicesProvider(provider)
verify(logger).logProviderUnregistered(numProviders = 0)
}
@Test
fun multipleProvidersRegisteredThenUnregistered_isLogged() {
val provider = TestProvider()
commandQueueCallbacks.registerNearbyMediaDevicesProvider(provider)
commandQueueCallbacks.registerNearbyMediaDevicesProvider(TestProvider())
commandQueueCallbacks.registerNearbyMediaDevicesProvider(TestProvider())
commandQueueCallbacks.unregisterNearbyMediaDevicesProvider(provider)
verify(logger).logProviderUnregistered(numProviders = 2)
}
@Test
fun providerUnregisteredButNeverRegistered_notLogged() {
commandQueueCallbacks.unregisterNearbyMediaDevicesProvider(TestProvider())
verify(logger, never()).logProviderRegistered(anyInt())
}
@Test
fun providerBinderDied_isLogged() {
val provider = TestProvider()
commandQueueCallbacks.registerNearbyMediaDevicesProvider(provider)
provider.deathRecipient!!.binderDied(provider)
verify(logger).logProviderBinderDied(numProviders = 0)
}
private class TestProvider : INearbyMediaDevicesProvider.Stub() {
var lastRegisteredCallback: INearbyMediaDevicesUpdateCallback? = null
var lastUnregisteredCallback: INearbyMediaDevicesUpdateCallback? = null
var deathRecipient: IBinder.DeathRecipient? = null
override fun registerNearbyDevicesCallback(
callback: INearbyMediaDevicesUpdateCallback
) {
@@ -142,5 +232,13 @@ class NearbyMediaDevicesManagerTest : SysuiTestCase() {
) {
lastUnregisteredCallback = callback
}
override fun asBinder(): IBinder {
return this
}
override fun linkToDeath(recipient: IBinder.DeathRecipient, flags: Int) {
deathRecipient = recipient
}
}
}