Loading packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +72 −24 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.GhostedViewLaunchAnimatorController; import com.android.systemui.animation.Interpolators; import com.android.systemui.bluetooth.BroadcastDialogController; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; Loading Loading @@ -188,6 +189,11 @@ public class MediaControlPanel { private final SeekBarViewModel.EnabledChangeListener mEnabledChangeListener = this::setIsSeekBarEnabled; private final BroadcastDialogController mBroadcastDialogController; private boolean mIsCurrentBroadcastedApp = false; private boolean mShowBroadcastDialogButton = false; private String mSwitchBroadcastApp; /** * Initialize a new control panel * Loading @@ -213,7 +219,8 @@ public class MediaControlPanel { MediaUiEventLogger logger, KeyguardStateController keyguardStateController, ActivityIntentHelper activityIntentHelper, NotificationLockscreenUserManager lockscreenUserManager) { NotificationLockscreenUserManager lockscreenUserManager, BroadcastDialogController broadcastDialogController) { mContext = context; mBackgroundExecutor = backgroundExecutor; mMainExecutor = mainExecutor; Loading @@ -230,6 +237,7 @@ public class MediaControlPanel { mKeyguardStateController = keyguardStateController; mActivityIntentHelper = activityIntentHelper; mLockscreenUserManager = lockscreenUserManager; mBroadcastDialogController = broadcastDialogController; mSeekBarViewModel.setLogSeek(() -> { if (mPackageName != null && mInstanceId != null) { Loading Loading @@ -449,7 +457,10 @@ public class MediaControlPanel { final MediaController controller = getController(); mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller)); bindOutputSwitcherChip(data); // Show the broadcast dialog button only when the le audio is enabled. mShowBroadcastDialogButton = data.getDevice() != null && data.getDevice().getShowBroadcastButton(); bindOutputSwitcherAndBroadcastButton(mShowBroadcastDialogButton, data); bindGutsMenuForPlayer(data); bindPlayerContentDescription(data); bindScrubbingTime(data); Loading @@ -467,21 +478,40 @@ public class MediaControlPanel { Trace.endSection(); } private void bindOutputSwitcherChip(MediaData data) { // Output switcher chip private void bindOutputSwitcherAndBroadcastButton(boolean showBroadcastButton, MediaData data) { ViewGroup seamlessView = mMediaViewHolder.getSeamless(); seamlessView.setVisibility(View.VISIBLE); ImageView iconView = mMediaViewHolder.getSeamlessIcon(); TextView deviceName = mMediaViewHolder.getSeamlessText(); final MediaDeviceData device = data.getDevice(); final boolean enabled; final boolean seamlessDisabled; final int iconResource; CharSequence deviceString; if (showBroadcastButton) { // TODO(b/233698402): Use the package name instead of app label to avoid the // unexpected result. mIsCurrentBroadcastedApp = device != null && TextUtils.equals(device.getName(), MediaDataUtils.getAppLabel(mContext, mPackageName, mContext.getString( R.string.bt_le_audio_broadcast_dialog_unknown_name))); seamlessDisabled = !mIsCurrentBroadcastedApp; // Always be enabled if the broadcast button is shown enabled = true; deviceString = mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name); iconResource = R.drawable.settings_input_antenna; } else { // Disable clicking on output switcher for invalid devices and resumption controls final boolean seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption(); final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f; mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha); seamlessView.setEnabled(!seamlessDisabled); CharSequence deviceString = mContext.getString(R.string.media_seamless_other_device); seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption(); enabled = !seamlessDisabled; deviceString = mContext.getString(R.string.media_seamless_other_device); iconResource = R.drawable.ic_media_home_devices; } mMediaViewHolder.getSeamlessButton().setAlpha(seamlessDisabled ? DISABLED_ALPHA : 1.0f); seamlessView.setEnabled(enabled); if (device != null) { Drawable icon = device.getIcon(); if (icon instanceof AdaptiveIcon) { Loading @@ -494,7 +524,7 @@ public class MediaControlPanel { deviceString = device.getName(); } else { // Set to default icon iconView.setImageResource(R.drawable.ic_media_home_devices); iconView.setImageResource(iconResource); } deviceName.setText(deviceString); seamlessView.setContentDescription(deviceString); Loading @@ -503,6 +533,23 @@ public class MediaControlPanel { if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return; } if (showBroadcastButton) { // If the current media app is not broadcasted and users press the outputer // button, we should pop up the broadcast dialog to check do they want to // switch broadcast to the other media app, otherwise we still pop up the // media output dialog. if (!mIsCurrentBroadcastedApp) { mLogger.logOpenBroadcastDialog(mUid, mPackageName, mInstanceId); mSwitchBroadcastApp = device.getName().toString(); mBroadcastDialogController.createBroadcastDialog(mSwitchBroadcastApp, mPackageName, true, mMediaViewHolder.getSeamlessButton()); } else { mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); mMediaOutputDialogFactory.create(mPackageName, true, mMediaViewHolder.getSeamlessButton()); } } else { mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); if (device.getIntent() != null) { if (device.getIntent().isActivity()) { Loading @@ -519,6 +566,7 @@ public class MediaControlPanel { mMediaOutputDialogFactory.create(mPackageName, true, mMediaViewHolder.getSeamlessButton()); } } }); } Loading packages/SystemUI/src/com/android/systemui/media/MediaData.kt +4 −1 Original line number Diff line number Diff line Loading @@ -215,5 +215,8 @@ data class MediaDeviceData val intent: PendingIntent? = null, /** Unique id for this device */ val id: String? = null val id: String? = null, /** Whether or not to show the broadcast button */ val showBroadcastButton: Boolean ) packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +2 −1 Original line number Diff line number Diff line Loading @@ -686,7 +686,8 @@ class MediaDataManager( val enabled = deviceIntent != null && deviceIntent.isActivity val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon) .loadDrawable(sbn.getPackageContext(context)) device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent) device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent, showBroadcastButton = false) } } Loading packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +134 −13 Original line number Diff line number Diff line Loading @@ -16,15 +16,23 @@ package com.android.systemui.media import android.bluetooth.BluetoothLeBroadcast import android.bluetooth.BluetoothLeBroadcastMetadata import android.content.Context import android.graphics.drawable.Drawable import android.media.MediaRouter2Manager import android.media.session.MediaController import android.text.TextUtils import android.util.Log import androidx.annotation.AnyThread import androidx.annotation.MainThread import androidx.annotation.WorkerThread import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.media.LocalMediaManager import com.android.settingslib.media.MediaDevice import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager Loading @@ -36,16 +44,20 @@ import java.util.concurrent.Executor import javax.inject.Inject private const val PLAYBACK_TYPE_UNKNOWN = 0 private const val TAG = "MediaDeviceManager" private const val DEBUG = true /** * Provides information about the route (ie. device) where playback is occurring. */ class MediaDeviceManager @Inject constructor( private val context: Context, private val controllerFactory: MediaControllerFactory, private val localMediaManagerFactory: LocalMediaManagerFactory, private val mr2manager: MediaRouter2Manager, private val muteAwaitConnectionManagerFactory: MediaMuteAwaitConnectionManagerFactory, private val configurationController: ConfigurationController, private val localBluetoothManager: LocalBluetoothManager?, @Main private val fgExecutor: Executor, @Background private val bgExecutor: Executor, dumpManager: DumpManager Loading Loading @@ -147,7 +159,8 @@ class MediaDeviceManager @Inject constructor( val controller: MediaController?, val localMediaManager: LocalMediaManager, val muteAwaitConnectionManager: MediaMuteAwaitConnectionManager? ) : LocalMediaManager.DeviceCallback, MediaController.Callback() { ) : LocalMediaManager.DeviceCallback, MediaController.Callback(), BluetoothLeBroadcast.Callback { val token get() = controller?.sessionToken Loading @@ -166,7 +179,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: AboutToConnectDevice? = null private var broadcastDescription: String? = null private val configListener = object : ConfigurationController.ConfigurationListener { override fun onLocaleListChanged() { updateCurrent() Loading Loading @@ -238,7 +251,11 @@ class MediaDeviceManager @Inject constructor( ) { aboutToConnectDeviceOverride = AboutToConnectDevice( fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress), backupMediaDeviceData = MediaDeviceData(enabled = true, deviceIcon, deviceName) backupMediaDeviceData = MediaDeviceData( /* enabled */ enabled = true, /* icon */ deviceIcon, /* name */ deviceName, /* showBroadcastButton */ showBroadcastButton = false) ) updateCurrent() } Loading @@ -248,8 +265,71 @@ class MediaDeviceManager @Inject constructor( updateCurrent() } override fun onBroadcastStarted(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStarted(), reason = $reason , broadcastId = $broadcastId") } updateCurrent() } override fun onBroadcastStartFailed(reason: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStartFailed(), reason = $reason") } } override fun onBroadcastMetadataChanged(broadcastId: Int, metadata: BluetoothLeBroadcastMetadata) { if (DEBUG) { Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " + "metadata = $metadata") } updateCurrent() } override fun onBroadcastStopped(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStopped(), reason = $reason , broadcastId = $broadcastId") } updateCurrent() } override fun onBroadcastStopFailed(reason: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStopFailed(), reason = $reason") } } override fun onBroadcastUpdated(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdated(), reason = $reason , broadcastId = $broadcastId") } updateCurrent() } override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdateFailed(), reason = $reason , " + "broadcastId = $broadcastId") } } override fun onPlaybackStarted(reason: Int, broadcastId: Int) {} override fun onPlaybackStopped(reason: Int, broadcastId: Int) {} @WorkerThread private fun updateCurrent() { if (isLeAudioBroadcastEnabled()) { current = MediaDeviceData( /* enabled */ true, /* icon */ context.getDrawable(R.drawable.settings_input_antenna), /* name */ broadcastDescription, /* intent */ null, /* showBroadcastButton */ showBroadcastButton = true) } else { val aboutToConnect = aboutToConnectDeviceOverride if (aboutToConnect != null && aboutToConnect.fullMediaDevice == null && Loading @@ -258,13 +338,54 @@ class MediaDeviceManager @Inject constructor( current = aboutToConnect.backupMediaDeviceData return } val device = aboutToConnect?.fullMediaDevice ?: 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 val enabled = device != null && (controller == null || route != null) val name = route?.name?.toString() ?: device?.name current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id) current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id, showBroadcastButton = false) } } private fun isLeAudioBroadcastEnabled(): Boolean { if (localBluetoothManager != null) { val profileManager = localBluetoothManager.profileManager if (profileManager != null) { val bluetoothLeBroadcast = profileManager.leAudioBroadcastProfile if (bluetoothLeBroadcast != null && bluetoothLeBroadcast.isEnabled(null)) { getBroadcastingInfo(bluetoothLeBroadcast) return true } else if (DEBUG) { Log.d(TAG, "Can not get LocalBluetoothLeBroadcast") } } else if (DEBUG) { Log.d(TAG, "Can not get LocalBluetoothProfileManager") } } else if (DEBUG) { Log.d(TAG, "Can not get LocalBluetoothManager") } return false } private fun getBroadcastingInfo(bluetoothLeBroadcast: LocalBluetoothLeBroadcast) { var currentBroadcastedApp = bluetoothLeBroadcast.appSourceName // TODO(b/233698402): Use the package name instead of app label to avoid the // unexpected result. // Check the current media app's name is the same with current broadcast app's name // or not. var mediaApp = MediaDataUtils.getAppLabel( context, localMediaManager.packageName, context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name)) var isCurrentBroadcastedApp = TextUtils.equals(mediaApp, currentBroadcastedApp) if (isCurrentBroadcastedApp) { broadcastDescription = context.getString( R.string.broadcasting_description_is_broadcasting) } else { broadcastDescription = currentBroadcastedApp } } } } Loading packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt +9 −1 Original line number Diff line number Diff line Loading @@ -176,6 +176,11 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger) logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 0, packageName, instanceId) } fun logOpenBroadcastDialog(uid: Int, packageName: String, instanceId: InstanceId) { logger.logWithInstanceId(MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG, uid, packageName, instanceId) } } enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { Loading Loading @@ -273,7 +278,10 @@ enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { MEDIA_RECOMMENDATION_ITEM_TAP(1044), @UiEvent(doc = "User tapped on a media recommendation card") MEDIA_RECOMMENDATION_CARD_TAP(1045); MEDIA_RECOMMENDATION_CARD_TAP(1045), @UiEvent(doc = "User opened the broadcast dialog from a media control") MEDIA_OPEN_BROADCAST_DIALOG(1079); override fun getId() = metricId } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +72 −24 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.GhostedViewLaunchAnimatorController; import com.android.systemui.animation.Interpolators; import com.android.systemui.bluetooth.BroadcastDialogController; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; Loading Loading @@ -188,6 +189,11 @@ public class MediaControlPanel { private final SeekBarViewModel.EnabledChangeListener mEnabledChangeListener = this::setIsSeekBarEnabled; private final BroadcastDialogController mBroadcastDialogController; private boolean mIsCurrentBroadcastedApp = false; private boolean mShowBroadcastDialogButton = false; private String mSwitchBroadcastApp; /** * Initialize a new control panel * Loading @@ -213,7 +219,8 @@ public class MediaControlPanel { MediaUiEventLogger logger, KeyguardStateController keyguardStateController, ActivityIntentHelper activityIntentHelper, NotificationLockscreenUserManager lockscreenUserManager) { NotificationLockscreenUserManager lockscreenUserManager, BroadcastDialogController broadcastDialogController) { mContext = context; mBackgroundExecutor = backgroundExecutor; mMainExecutor = mainExecutor; Loading @@ -230,6 +237,7 @@ public class MediaControlPanel { mKeyguardStateController = keyguardStateController; mActivityIntentHelper = activityIntentHelper; mLockscreenUserManager = lockscreenUserManager; mBroadcastDialogController = broadcastDialogController; mSeekBarViewModel.setLogSeek(() -> { if (mPackageName != null && mInstanceId != null) { Loading Loading @@ -449,7 +457,10 @@ public class MediaControlPanel { final MediaController controller = getController(); mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller)); bindOutputSwitcherChip(data); // Show the broadcast dialog button only when the le audio is enabled. mShowBroadcastDialogButton = data.getDevice() != null && data.getDevice().getShowBroadcastButton(); bindOutputSwitcherAndBroadcastButton(mShowBroadcastDialogButton, data); bindGutsMenuForPlayer(data); bindPlayerContentDescription(data); bindScrubbingTime(data); Loading @@ -467,21 +478,40 @@ public class MediaControlPanel { Trace.endSection(); } private void bindOutputSwitcherChip(MediaData data) { // Output switcher chip private void bindOutputSwitcherAndBroadcastButton(boolean showBroadcastButton, MediaData data) { ViewGroup seamlessView = mMediaViewHolder.getSeamless(); seamlessView.setVisibility(View.VISIBLE); ImageView iconView = mMediaViewHolder.getSeamlessIcon(); TextView deviceName = mMediaViewHolder.getSeamlessText(); final MediaDeviceData device = data.getDevice(); final boolean enabled; final boolean seamlessDisabled; final int iconResource; CharSequence deviceString; if (showBroadcastButton) { // TODO(b/233698402): Use the package name instead of app label to avoid the // unexpected result. mIsCurrentBroadcastedApp = device != null && TextUtils.equals(device.getName(), MediaDataUtils.getAppLabel(mContext, mPackageName, mContext.getString( R.string.bt_le_audio_broadcast_dialog_unknown_name))); seamlessDisabled = !mIsCurrentBroadcastedApp; // Always be enabled if the broadcast button is shown enabled = true; deviceString = mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name); iconResource = R.drawable.settings_input_antenna; } else { // Disable clicking on output switcher for invalid devices and resumption controls final boolean seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption(); final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f; mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha); seamlessView.setEnabled(!seamlessDisabled); CharSequence deviceString = mContext.getString(R.string.media_seamless_other_device); seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption(); enabled = !seamlessDisabled; deviceString = mContext.getString(R.string.media_seamless_other_device); iconResource = R.drawable.ic_media_home_devices; } mMediaViewHolder.getSeamlessButton().setAlpha(seamlessDisabled ? DISABLED_ALPHA : 1.0f); seamlessView.setEnabled(enabled); if (device != null) { Drawable icon = device.getIcon(); if (icon instanceof AdaptiveIcon) { Loading @@ -494,7 +524,7 @@ public class MediaControlPanel { deviceString = device.getName(); } else { // Set to default icon iconView.setImageResource(R.drawable.ic_media_home_devices); iconView.setImageResource(iconResource); } deviceName.setText(deviceString); seamlessView.setContentDescription(deviceString); Loading @@ -503,6 +533,23 @@ public class MediaControlPanel { if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return; } if (showBroadcastButton) { // If the current media app is not broadcasted and users press the outputer // button, we should pop up the broadcast dialog to check do they want to // switch broadcast to the other media app, otherwise we still pop up the // media output dialog. if (!mIsCurrentBroadcastedApp) { mLogger.logOpenBroadcastDialog(mUid, mPackageName, mInstanceId); mSwitchBroadcastApp = device.getName().toString(); mBroadcastDialogController.createBroadcastDialog(mSwitchBroadcastApp, mPackageName, true, mMediaViewHolder.getSeamlessButton()); } else { mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); mMediaOutputDialogFactory.create(mPackageName, true, mMediaViewHolder.getSeamlessButton()); } } else { mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); if (device.getIntent() != null) { if (device.getIntent().isActivity()) { Loading @@ -519,6 +566,7 @@ public class MediaControlPanel { mMediaOutputDialogFactory.create(mPackageName, true, mMediaViewHolder.getSeamlessButton()); } } }); } Loading
packages/SystemUI/src/com/android/systemui/media/MediaData.kt +4 −1 Original line number Diff line number Diff line Loading @@ -215,5 +215,8 @@ data class MediaDeviceData val intent: PendingIntent? = null, /** Unique id for this device */ val id: String? = null val id: String? = null, /** Whether or not to show the broadcast button */ val showBroadcastButton: Boolean )
packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +2 −1 Original line number Diff line number Diff line Loading @@ -686,7 +686,8 @@ class MediaDataManager( val enabled = deviceIntent != null && deviceIntent.isActivity val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon) .loadDrawable(sbn.getPackageContext(context)) device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent) device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent, showBroadcastButton = false) } } Loading
packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +134 −13 Original line number Diff line number Diff line Loading @@ -16,15 +16,23 @@ package com.android.systemui.media import android.bluetooth.BluetoothLeBroadcast import android.bluetooth.BluetoothLeBroadcastMetadata import android.content.Context import android.graphics.drawable.Drawable import android.media.MediaRouter2Manager import android.media.session.MediaController import android.text.TextUtils import android.util.Log import androidx.annotation.AnyThread import androidx.annotation.MainThread import androidx.annotation.WorkerThread import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.media.LocalMediaManager import com.android.settingslib.media.MediaDevice import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager Loading @@ -36,16 +44,20 @@ import java.util.concurrent.Executor import javax.inject.Inject private const val PLAYBACK_TYPE_UNKNOWN = 0 private const val TAG = "MediaDeviceManager" private const val DEBUG = true /** * Provides information about the route (ie. device) where playback is occurring. */ class MediaDeviceManager @Inject constructor( private val context: Context, private val controllerFactory: MediaControllerFactory, private val localMediaManagerFactory: LocalMediaManagerFactory, private val mr2manager: MediaRouter2Manager, private val muteAwaitConnectionManagerFactory: MediaMuteAwaitConnectionManagerFactory, private val configurationController: ConfigurationController, private val localBluetoothManager: LocalBluetoothManager?, @Main private val fgExecutor: Executor, @Background private val bgExecutor: Executor, dumpManager: DumpManager Loading Loading @@ -147,7 +159,8 @@ class MediaDeviceManager @Inject constructor( val controller: MediaController?, val localMediaManager: LocalMediaManager, val muteAwaitConnectionManager: MediaMuteAwaitConnectionManager? ) : LocalMediaManager.DeviceCallback, MediaController.Callback() { ) : LocalMediaManager.DeviceCallback, MediaController.Callback(), BluetoothLeBroadcast.Callback { val token get() = controller?.sessionToken Loading @@ -166,7 +179,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: AboutToConnectDevice? = null private var broadcastDescription: String? = null private val configListener = object : ConfigurationController.ConfigurationListener { override fun onLocaleListChanged() { updateCurrent() Loading Loading @@ -238,7 +251,11 @@ class MediaDeviceManager @Inject constructor( ) { aboutToConnectDeviceOverride = AboutToConnectDevice( fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress), backupMediaDeviceData = MediaDeviceData(enabled = true, deviceIcon, deviceName) backupMediaDeviceData = MediaDeviceData( /* enabled */ enabled = true, /* icon */ deviceIcon, /* name */ deviceName, /* showBroadcastButton */ showBroadcastButton = false) ) updateCurrent() } Loading @@ -248,8 +265,71 @@ class MediaDeviceManager @Inject constructor( updateCurrent() } override fun onBroadcastStarted(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStarted(), reason = $reason , broadcastId = $broadcastId") } updateCurrent() } override fun onBroadcastStartFailed(reason: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStartFailed(), reason = $reason") } } override fun onBroadcastMetadataChanged(broadcastId: Int, metadata: BluetoothLeBroadcastMetadata) { if (DEBUG) { Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " + "metadata = $metadata") } updateCurrent() } override fun onBroadcastStopped(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStopped(), reason = $reason , broadcastId = $broadcastId") } updateCurrent() } override fun onBroadcastStopFailed(reason: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastStopFailed(), reason = $reason") } } override fun onBroadcastUpdated(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdated(), reason = $reason , broadcastId = $broadcastId") } updateCurrent() } override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) { if (DEBUG) { Log.d(TAG, "onBroadcastUpdateFailed(), reason = $reason , " + "broadcastId = $broadcastId") } } override fun onPlaybackStarted(reason: Int, broadcastId: Int) {} override fun onPlaybackStopped(reason: Int, broadcastId: Int) {} @WorkerThread private fun updateCurrent() { if (isLeAudioBroadcastEnabled()) { current = MediaDeviceData( /* enabled */ true, /* icon */ context.getDrawable(R.drawable.settings_input_antenna), /* name */ broadcastDescription, /* intent */ null, /* showBroadcastButton */ showBroadcastButton = true) } else { val aboutToConnect = aboutToConnectDeviceOverride if (aboutToConnect != null && aboutToConnect.fullMediaDevice == null && Loading @@ -258,13 +338,54 @@ class MediaDeviceManager @Inject constructor( current = aboutToConnect.backupMediaDeviceData return } val device = aboutToConnect?.fullMediaDevice ?: 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 val enabled = device != null && (controller == null || route != null) val name = route?.name?.toString() ?: device?.name current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id) current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id, showBroadcastButton = false) } } private fun isLeAudioBroadcastEnabled(): Boolean { if (localBluetoothManager != null) { val profileManager = localBluetoothManager.profileManager if (profileManager != null) { val bluetoothLeBroadcast = profileManager.leAudioBroadcastProfile if (bluetoothLeBroadcast != null && bluetoothLeBroadcast.isEnabled(null)) { getBroadcastingInfo(bluetoothLeBroadcast) return true } else if (DEBUG) { Log.d(TAG, "Can not get LocalBluetoothLeBroadcast") } } else if (DEBUG) { Log.d(TAG, "Can not get LocalBluetoothProfileManager") } } else if (DEBUG) { Log.d(TAG, "Can not get LocalBluetoothManager") } return false } private fun getBroadcastingInfo(bluetoothLeBroadcast: LocalBluetoothLeBroadcast) { var currentBroadcastedApp = bluetoothLeBroadcast.appSourceName // TODO(b/233698402): Use the package name instead of app label to avoid the // unexpected result. // Check the current media app's name is the same with current broadcast app's name // or not. var mediaApp = MediaDataUtils.getAppLabel( context, localMediaManager.packageName, context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name)) var isCurrentBroadcastedApp = TextUtils.equals(mediaApp, currentBroadcastedApp) if (isCurrentBroadcastedApp) { broadcastDescription = context.getString( R.string.broadcasting_description_is_broadcasting) } else { broadcastDescription = currentBroadcastedApp } } } } Loading
packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt +9 −1 Original line number Diff line number Diff line Loading @@ -176,6 +176,11 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger) logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 0, packageName, instanceId) } fun logOpenBroadcastDialog(uid: Int, packageName: String, instanceId: InstanceId) { logger.logWithInstanceId(MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG, uid, packageName, instanceId) } } enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { Loading Loading @@ -273,7 +278,10 @@ enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { MEDIA_RECOMMENDATION_ITEM_TAP(1044), @UiEvent(doc = "User tapped on a media recommendation card") MEDIA_RECOMMENDATION_CARD_TAP(1045); MEDIA_RECOMMENDATION_CARD_TAP(1045), @UiEvent(doc = "User opened the broadcast dialog from a media control") MEDIA_OPEN_BROADCAST_DIALOG(1079); override fun getId() = metricId } No newline at end of file