diff --git a/res/values/strings.xml b/res/values/strings.xml index 7998c1ef344..6ed0d820dc4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10927,6 +10927,9 @@ Play %s on + + Audio will play on + This device diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java index e2232e71c2f..bb075c2f7e3 100644 --- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java +++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java @@ -17,6 +17,7 @@ package com.android.settings.media; import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; +import static com.android.settingslib.media.flags.Flags.enableOutputSwitcherForSystemRouting; import android.annotation.ColorInt; import android.content.Context; @@ -58,7 +59,12 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { } final IconCompat icon = IconCompat.createWithResource(mContext, com.android.internal.R.drawable.ic_settings_bluetooth); - final CharSequence title = mContext.getString(R.string.media_output_label_title, + final int stringRes = enableOutputSwitcherForSystemRouting() + ? (getWorker().getActiveLocalMediaController() != null + ? R.string.media_output_label_title + : R.string.media_output_title_without_playing) + : R.string.media_output_label_title; + final CharSequence title = mContext.getString(stringRes, Utils.getApplicationLabel(mContext, getWorker().getPackageName())); final SliceAction primarySliceAction = SliceAction.create( getBroadcastIntent(mContext), icon, ListBuilder.ICON_IMAGE, title); @@ -117,28 +123,36 @@ public class MediaOutputIndicatorSlice implements CustomSliceable { // 2. worker is not null // 3. Available devices are more than 0 // 4. The local media session is active and the state is playing. + // - if !enableOutputSwitcherForSystemRouting(), (4) will be bypass. return getWorker() != null && !com.android.settingslib.Utils.isAudioModeOngoingCall(mContext) && getWorker().getMediaDevices().size() > 0 - && getWorker().getActiveLocalMediaController() != null; + && (enableOutputSwitcherForSystemRouting() + ? true : getWorker().getActiveLocalMediaController() != null); } @Override public void onNotifyChange(Intent intent) { final MediaController mediaController = getWorker().getActiveLocalMediaController(); - if (mediaController == null) { + // Launch media output dialog + if (enableOutputSwitcherForSystemRouting() && mediaController == null) { + mContext.sendBroadcast(new Intent() + .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME) + .setAction(MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG)); + } else if (mediaController != null) { + mContext.sendBroadcast(new Intent() + .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME) + .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .putExtra(MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN, + mediaController.getSessionToken()) + .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, + mediaController.getPackageName())); + } else { Log.d(TAG, "No active local media controller"); return; } - // Launch media output dialog - mContext.sendBroadcast(new Intent() - .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME) - .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) - .putExtra(MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN, - mediaController.getSessionToken()) - .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, - mediaController.getPackageName())); + // Dismiss volume panel mContext.sendBroadcast(new Intent() .setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME) diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index 6475257b29c..b570b2dff97 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -18,6 +18,9 @@ package com.android.settings.sound; import static android.media.AudioManager.STREAM_DEVICES_CHANGED_ACTION; +import static com.android.settingslib.media.flags.Flags.enableOutputSwitcherForSystemRouting; + +import android.annotation.Nullable; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; @@ -28,6 +31,8 @@ import android.media.AudioDeviceCallback; import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.MediaRouter; +import android.media.session.MediaController; +import android.media.session.MediaSessionManager; import android.os.Handler; import android.os.Looper; import android.util.FeatureFlagUtils; @@ -79,6 +84,8 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont private final WiredHeadsetBroadcastReceiver mReceiver; private final Handler mHandler; private LocalBluetoothManager mLocalBluetoothManager; + @Nullable private MediaSessionManager.OnActiveSessionsChangedListener mSessionListener; + @Nullable private MediaSessionManager mMediaSessionManager; public interface AudioSwitchCallback { void onPreferenceDataChanged(ListPreference preference); @@ -107,6 +114,14 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont return; } mProfileManager = mLocalBluetoothManager.getProfileManager(); + + if (enableOutputSwitcherForSystemRouting()) { + mMediaSessionManager = context.getSystemService(MediaSessionManager.class); + mSessionListener = new SessionChangeListener(); + } else { + mMediaSessionManager = null; + mSessionListener = null; + } } /** @@ -329,13 +344,27 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont // Register for misc other intent broadcasts. IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); intentFilter.addAction(STREAM_DEVICES_CHANGED_ACTION); - mContext.registerReceiver(mReceiver, intentFilter); + + if (enableOutputSwitcherForSystemRouting()) { + mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED); + if (mMediaSessionManager != null) { + mMediaSessionManager.addOnActiveSessionsChangedListener( + mSessionListener, null, mHandler); + } + } else { + mContext.registerReceiver(mReceiver, intentFilter); + } } private void unregister() { mLocalBluetoothManager.getEventManager().unregisterCallback(this); mAudioManager.unregisterAudioDeviceCallback(mAudioManagerAudioDeviceCallback); mContext.unregisterReceiver(mReceiver); + if (enableOutputSwitcherForSystemRouting()) { + if (mMediaSessionManager != null) { + mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionListener); + } + } } /** Notifications of audio device connection and disconnection events. */ @@ -362,4 +391,12 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont } } } + + private class SessionChangeListener + implements MediaSessionManager.OnActiveSessionsChangedListener { + @Override + public void onActiveSessionsChanged(List controllers) { + updateState(mPreference); + } + } } diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java index 758f7e33383..47be7fe9bd3 100644 --- a/src/com/android/settings/sound/MediaOutputPreferenceController.java +++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java @@ -16,6 +16,9 @@ package com.android.settings.sound; +import static com.android.settingslib.media.flags.Flags.enableOutputSwitcherForSystemRouting; + +import android.annotation.Nullable; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.Intent; @@ -46,21 +49,22 @@ import java.util.List; */ public class MediaOutputPreferenceController extends AudioSwitchPreferenceController { - private MediaController mMediaController; + private static final String TAG = "MediaOutputPreferenceController"; + @Nullable private MediaController mMediaController; + private MediaSessionManager mMediaSessionManager; public MediaOutputPreferenceController(Context context, String key) { super(context, key); - mMediaController = MediaOutputUtils.getActiveLocalMediaController(context.getSystemService( - MediaSessionManager.class)); + mMediaSessionManager = context.getSystemService(MediaSessionManager.class); + mMediaController = MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager); } @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - if (!Utils.isAudioModeOngoingCall(mContext) && mMediaController != null) { - mPreference.setVisible(true); - } + mPreference.setVisible(!Utils.isAudioModeOngoingCall(mContext) + && (enableOutputSwitcherForSystemRouting() ? true : mMediaController != null)); } @Override @@ -70,11 +74,16 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro return; } - if (mMediaController == null) { - // No active local playback - return; + if (enableOutputSwitcherForSystemRouting()) { + mMediaController = MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager); + } else { + if (mMediaController == null) { + // No active local playback + return; + } } + if (Utils.isAudioModeOngoingCall(mContext)) { // Ongoing call status, switch entry for media will be disabled. mPreference.setVisible(false); @@ -95,9 +104,14 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro || (connectedLeAudioDevices != null && !connectedLeAudioDevices.isEmpty()))) { activeDevice = findActiveDevice(); } - mPreference.setTitle(mContext.getString(R.string.media_output_label_title, - com.android.settings.Utils.getApplicationLabel(mContext, - mMediaController.getPackageName()))); + + if (mMediaController == null) { + mPreference.setTitle(mContext.getString(R.string.media_output_title_without_playing)); + } else { + mPreference.setTitle(mContext.getString(R.string.media_output_label_title, + com.android.settings.Utils.getApplicationLabel(mContext, + mMediaController.getPackageName()))); + } mPreference.setSummary((activeDevice == null) ? mContext.getText(R.string.media_output_default_summary) : activeDevice.getAlias()); @@ -145,13 +159,19 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro @Override public boolean handlePreferenceTreeClick(Preference preference) { if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { - mContext.sendBroadcast(new Intent() - .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) - .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME) - .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, - mMediaController.getPackageName()) - .putExtra(MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN, - mMediaController.getSessionToken())); + if (enableOutputSwitcherForSystemRouting() && mMediaController == null) { + mContext.sendBroadcast(new Intent() + .setAction(MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME)); + } else if (mMediaController != null) { + mContext.sendBroadcast(new Intent() + .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG) + .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME) + .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, + mMediaController.getPackageName()) + .putExtra(MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN, + mMediaController.getSessionToken())); + } return true; } return false; diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java index a91f627ecb5..652bd039b45 100644 --- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java +++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java @@ -18,6 +18,7 @@ package com.android.settings.media; import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; +import static com.android.settingslib.media.flags.Flags.FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING; import static com.google.common.truth.Truth.assertThat; @@ -38,6 +39,7 @@ import android.media.session.MediaController; import android.media.session.MediaSession; import android.net.Uri; import android.os.Process; +import android.platform.test.flag.junit.SetFlagsRule; import android.text.TextUtils; import androidx.slice.Slice; @@ -55,6 +57,7 @@ import com.android.settingslib.media.MediaOutputConstants; import org.junit.Before; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -96,6 +99,9 @@ public class MediaOutputIndicatorSliceTest { @Mock private Drawable mTestDrawable; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private Context mContext; private MediaOutputIndicatorSlice mMediaOutputIndicatorSlice; private AudioManager mAudioManager; @@ -254,6 +260,34 @@ public class MediaOutputIndicatorSliceTest { MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN) == null).isTrue(); } + @Test + public void onNotifyChange_withoutMediaControllerFlagEnabled_verifyIntentExtra() { + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + doReturn(null).when(sMediaOutputIndicatorWorker) + .getActiveLocalMediaController(); + ArgumentCaptor argument = ArgumentCaptor.forClass(Intent.class); + + mMediaOutputIndicatorSlice.onNotifyChange(null); + verify(mContext, times(2)).sendBroadcast(argument.capture()); + List intentList = argument.getAllValues(); + Intent intent = intentList.get(0); + + assertThat(intent.getAction()).isEqualTo( + MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG); + assertThat(TextUtils.equals(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME, + intent.getPackage())).isTrue(); + } + + @Test + public void onNotifyChange_withoutMediaControllerFlagDisabled_doNothing() { + mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + doReturn(null).when(sMediaOutputIndicatorWorker) + .getActiveLocalMediaController(); + + mMediaOutputIndicatorSlice.onNotifyChange(null); + } + + @Test public void isVisible_allConditionMatched_returnTrue() { mAudioManager.setMode(AudioManager.MODE_NORMAL); @@ -268,6 +302,7 @@ public class MediaOutputIndicatorSliceTest { @Test public void isVisible_noActiveSession_returnFalse() { + mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); mAudioManager.setMode(AudioManager.MODE_NORMAL); mDevices.add(mDevice1); @@ -278,6 +313,19 @@ public class MediaOutputIndicatorSliceTest { assertThat(mMediaOutputIndicatorSlice.isVisible()).isFalse(); } + @Test + public void isVisible_noActiveSession_returnTrue() { + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + mAudioManager.setMode(AudioManager.MODE_NORMAL); + mDevices.add(mDevice1); + + when(sMediaOutputIndicatorWorker.getMediaDevices()).thenReturn(mDevices); + doReturn(mMediaController).when(sMediaOutputIndicatorWorker) + .getActiveLocalMediaController(); + + assertThat(mMediaOutputIndicatorSlice.isVisible()).isTrue(); + } + private void initPackage() { mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager()); mAppInfo = new ApplicationInfo(); diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java index 151d1f289c1..a272d9c8ac3 100644 --- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java @@ -21,10 +21,12 @@ import static android.media.AudioSystem.STREAM_MUSIC; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settingslib.media.flags.Flags.FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -38,6 +40,8 @@ import android.content.Context; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.media.AudioManager; +import android.media.session.MediaSessionManager; +import android.platform.test.flag.junit.SetFlagsRule; import android.util.FeatureFlagUtils; import androidx.preference.ListPreference; @@ -61,6 +65,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -113,6 +118,9 @@ public class AudioOutputSwitchPreferenceControllerTest { @Mock private CachedBluetoothDevice mCachedBluetoothDeviceR; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private Context mContext; private PreferenceScreen mScreen; private ListPreference mPreference; @@ -238,6 +246,7 @@ public class AudioOutputSwitchPreferenceControllerTest { @Test public void onStart_shouldRegisterCallbackAndRegisterReceiver() { + mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); mController.onStart(); verify(mLocalBluetoothManager.getEventManager()).registerCallback( @@ -248,6 +257,7 @@ public class AudioOutputSwitchPreferenceControllerTest { @Test public void onStop_shouldUnregisterCallbackAndUnregisterReceiver() { + mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); mController.onStart(); mController.onStop(); @@ -257,6 +267,45 @@ public class AudioOutputSwitchPreferenceControllerTest { verify(mLocalBluetoothManager).setForegroundActivity(null); } + @Test + public void onStart_shouldRegisterCallbackAndRegisterReceiverWithDefaultMediaOutput() { + MediaSessionManager mediaSessionManager = + spy(mContext.getSystemService(MediaSessionManager.class)); + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mediaSessionManager); + mController = new AudioSwitchPreferenceControllerTestable(mContext, TEST_KEY); + + mController.onStart(); + + verify(mLocalBluetoothManager.getEventManager()).registerCallback( + any(BluetoothCallback.class)); + verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class), + eq(Context.RECEIVER_NOT_EXPORTED)); + verify(mLocalBluetoothManager).setForegroundActivity(mContext); + verify(mediaSessionManager).addOnActiveSessionsChangedListener( + any(MediaSessionManager.OnActiveSessionsChangedListener.class), any(), any()); + } + + + @Test + public void onStop_shouldUnregisterCallbackAndUnregisterReceiverWithDefaultMediaOutput() { + MediaSessionManager mediaSessionManager = + spy(mContext.getSystemService(MediaSessionManager.class)); + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mediaSessionManager); + mController = new AudioSwitchPreferenceControllerTestable(mContext, TEST_KEY); + mController.onStart(); + + mController.onStop(); + + verify(mLocalBluetoothManager.getEventManager()).unregisterCallback( + any(BluetoothCallback.class)); + verify(mContext).unregisterReceiver(any(BroadcastReceiver.class)); + verify(mLocalBluetoothManager).setForegroundActivity(null); + verify(mediaSessionManager).removeOnActiveSessionsChangedListener( + any(MediaSessionManager.OnActiveSessionsChangedListener.class)); + } + /** * Audio stream output to bluetooth sco headset which is the subset of all sco device. * isStreamFromOutputDevice should return true. diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java index 5a92a0838a1..b9f9b168ac5 100644 --- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java @@ -21,6 +21,8 @@ import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; import static android.media.AudioSystem.DEVICE_OUT_EARPIECE; import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID; +import static com.android.settingslib.media.flags.Flags.FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -45,6 +47,7 @@ import android.media.VolumeProvider; import android.media.session.MediaController; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.preference.Preference; import androidx.preference.PreferenceManager; @@ -66,6 +69,7 @@ import com.android.settingslib.media.MediaOutputConstants; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -103,6 +107,9 @@ public class MediaOutputPreferenceControllerTest { private static final String TEST_PACKAGE_NAME = "com.test.packagename"; private static final String TEST_APPLICATION_LABEL = "APP Test Label"; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private LocalBluetoothManager mLocalManager; @Mock @@ -227,6 +234,8 @@ public class MediaOutputPreferenceControllerTest { mScreen.addPreference(mPreference); mController.displayPreference(mScreen); mController.setCallback(mAudioSwitchPreferenceCallback); + + mSetFlagsRule.initAllFlagsToReleaseConfigDefault(); } @After @@ -314,6 +323,7 @@ public class MediaOutputPreferenceControllerTest { @Test public void updateState_noActiveLocalPlayback_noTitle() { + mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); mPlaybackState = new PlaybackState.Builder() .setState(PlaybackState.STATE_NONE, 0, 1) .build(); @@ -325,6 +335,48 @@ public class MediaOutputPreferenceControllerTest { assertThat(mPreference.getTitle()).isNull(); } + @Test + public void updateState_noActiveLocalPlayback_checkTitle() { + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + mPlaybackState = new PlaybackState.Builder() + .setState(PlaybackState.STATE_NONE, 0, 1) + .build(); + when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); + mController = new MediaOutputPreferenceController(mContext, TEST_KEY); + mController.displayPreference(mScreen); + + mController.updateState(mPreference); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.media_output_title_without_playing, + TEST_APPLICATION_LABEL)); + } + + @Test + public void updateState_withNullMediaController_noTitle() { + mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + mMediaControllers.clear(); + mController = new MediaOutputPreferenceController(mContext, TEST_KEY); + + mController.updateState(mPreference); + + assertThat(mPreference.getTitle()).isNull(); + } + + @Test + public void updateState_withNullMediaController_checkTitle() { + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + mMediaControllers.clear(); + mController = new MediaOutputPreferenceController(mContext, TEST_KEY); + mController.displayPreference(mScreen); + + mController.updateState(mPreference); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.media_output_title_without_playing, + TEST_APPLICATION_LABEL)); + } + @Test public void updateState_withActiveLocalPlayback_checkTitle() { initPackage(); @@ -349,6 +401,39 @@ public class MediaOutputPreferenceControllerTest { .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG); } + @Test + public void handlePreferenceTreeClick_WithNoLocalPlaybackFlagEnabled_verifyIntentExtra() { + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); + mPlaybackState = new PlaybackState.Builder() + .setState(PlaybackState.STATE_NONE, 0, 1) + .build(); + when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState); + mController = new MediaOutputPreferenceController(mContext, TEST_KEY); + mPreference.setKey(TEST_KEY); + + mController.handlePreferenceTreeClick(mPreference); + + verify(mContext).sendBroadcast(intentCaptor.capture()); + assertThat(intentCaptor.getValue().getAction()) + .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG); + } + + @Test + public void handlePreferenceTreeClick_WithNullControllerFlagEnabled_verifyIntentExtra() { + mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING); + final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); + mMediaControllers.clear(); + mController = new MediaOutputPreferenceController(mContext, TEST_KEY); + mPreference.setKey(TEST_KEY); + + mController.handlePreferenceTreeClick(mPreference); + + verify(mContext).sendBroadcast(intentCaptor.capture()); + assertThat(intentCaptor.getValue().getAction()) + .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_SYSTEM_MEDIA_OUTPUT_DIALOG); + } + /** * Default status * Preference should be invisible