Update "Play media to" in Sound Settings
-Change string to "Play <APP Label> on" -Hide it when there is no local playback -Disable search index -Add test cases Bug: 155720628 Test: make -j50 RunSettingsRoboTests Change-Id: Id104d5b49c069a761e4cf82385bf1225d494c95e
This commit is contained in:
@@ -45,6 +45,7 @@
|
|||||||
android:title="@string/media_output_title"
|
android:title="@string/media_output_title"
|
||||||
android:dialogTitle="@string/media_output_title"
|
android:dialogTitle="@string/media_output_title"
|
||||||
android:order="-175"
|
android:order="-175"
|
||||||
|
settings:searchable="false"
|
||||||
settings:controller="com.android.settings.sound.MediaOutputPreferenceController"/>
|
settings:controller="com.android.settings.sound.MediaOutputPreferenceController"/>
|
||||||
|
|
||||||
<!-- Call volume -->
|
<!-- Call volume -->
|
||||||
|
@@ -20,8 +20,12 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.media.session.MediaController;
|
||||||
|
import android.media.session.MediaSessionManager;
|
||||||
|
import android.media.session.PlaybackState;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
@@ -43,15 +47,18 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class MediaOutputPreferenceController extends AudioSwitchPreferenceController {
|
public class MediaOutputPreferenceController extends AudioSwitchPreferenceController {
|
||||||
|
|
||||||
|
private MediaController mMediaController;
|
||||||
|
|
||||||
public MediaOutputPreferenceController(Context context, String key) {
|
public MediaOutputPreferenceController(Context context, String key) {
|
||||||
super(context, key);
|
super(context, key);
|
||||||
|
mMediaController = getActiveLocalMediaController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
super.displayPreference(screen);
|
super.displayPreference(screen);
|
||||||
|
|
||||||
if (!Utils.isAudioModeOngoingCall(mContext)) {
|
if (!Utils.isAudioModeOngoingCall(mContext) && mMediaController != null) {
|
||||||
mPreference.setVisible(true);
|
mPreference.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,6 +70,11 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mMediaController == null) {
|
||||||
|
// No active local playback
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Utils.isAudioModeOngoingCall(mContext)) {
|
if (Utils.isAudioModeOngoingCall(mContext)) {
|
||||||
// Ongoing call status, switch entry for media will be disabled.
|
// Ongoing call status, switch entry for media will be disabled.
|
||||||
mPreference.setVisible(false);
|
mPreference.setVisible(false);
|
||||||
@@ -81,6 +93,9 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
|
|||||||
|| (connectedHADevices != null && !connectedHADevices.isEmpty()))) {
|
|| (connectedHADevices != null && !connectedHADevices.isEmpty()))) {
|
||||||
activeDevice = findActiveDevice();
|
activeDevice = findActiveDevice();
|
||||||
}
|
}
|
||||||
|
mPreference.setTitle(mContext.getString(R.string.media_output_label_title,
|
||||||
|
com.android.settings.Utils.getApplicationLabel(mContext,
|
||||||
|
mMediaController.getPackageName())));
|
||||||
mPreference.setSummary((activeDevice == null) ?
|
mPreference.setSummary((activeDevice == null) ?
|
||||||
mContext.getText(R.string.media_output_default_summary) :
|
mContext.getText(R.string.media_output_default_summary) :
|
||||||
activeDevice.getAlias());
|
activeDevice.getAlias());
|
||||||
@@ -126,4 +141,26 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
MediaController getActiveLocalMediaController() {
|
||||||
|
final MediaSessionManager mMediaSessionManager = mContext.getSystemService(
|
||||||
|
MediaSessionManager.class);
|
||||||
|
|
||||||
|
for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
|
||||||
|
final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
|
||||||
|
if (pi == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final PlaybackState playbackState = controller.getPlaybackState();
|
||||||
|
if (playbackState == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
|
||||||
|
&& playbackState.getState() == PlaybackState.STATE_PLAYING) {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
@@ -33,7 +34,15 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.bluetooth.BluetoothManager;
|
import android.bluetooth.BluetoothManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageStats;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.media.VolumeProvider;
|
||||||
|
import android.media.session.MediaController;
|
||||||
|
import android.media.session.MediaSessionManager;
|
||||||
|
import android.media.session.PlaybackState;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
@@ -60,8 +69,10 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.Shadows;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowBluetoothDevice;
|
import org.robolectric.shadows.ShadowBluetoothDevice;
|
||||||
|
import org.robolectric.shadows.ShadowPackageManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -82,6 +93,8 @@ public class MediaOutputPreferenceControllerTest {
|
|||||||
private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
|
private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
|
||||||
private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
|
private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
|
||||||
private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4";
|
private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4";
|
||||||
|
private static final String TEST_PACKAGE_NAME = "com.test.packagename";
|
||||||
|
private static final String TEST_APPLICATION_LABEL = "APP Test Label";
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private LocalBluetoothManager mLocalManager;
|
private LocalBluetoothManager mLocalManager;
|
||||||
@@ -95,6 +108,10 @@ public class MediaOutputPreferenceControllerTest {
|
|||||||
private HearingAidProfile mHearingAidProfile;
|
private HearingAidProfile mHearingAidProfile;
|
||||||
@Mock
|
@Mock
|
||||||
private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback;
|
private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback;
|
||||||
|
@Mock
|
||||||
|
private MediaSessionManager mMediaSessionManager;
|
||||||
|
@Mock
|
||||||
|
private MediaController mMediaController;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private PreferenceScreen mScreen;
|
private PreferenceScreen mScreen;
|
||||||
@@ -111,6 +128,13 @@ public class MediaOutputPreferenceControllerTest {
|
|||||||
private MediaOutputPreferenceController mController;
|
private MediaOutputPreferenceController mController;
|
||||||
private List<BluetoothDevice> mProfileConnectedDevices;
|
private List<BluetoothDevice> mProfileConnectedDevices;
|
||||||
private List<BluetoothDevice> mHearingAidActiveDevices;
|
private List<BluetoothDevice> mHearingAidActiveDevices;
|
||||||
|
private List<MediaController> mMediaControllers = new ArrayList<>();
|
||||||
|
private MediaController.PlaybackInfo mPlaybackInfo;
|
||||||
|
private PlaybackState mPlaybackState;
|
||||||
|
private ShadowPackageManager mShadowPackageManager;
|
||||||
|
private ApplicationInfo mAppInfo;
|
||||||
|
private PackageInfo mPackageInfo;
|
||||||
|
private PackageStats mPackageStats;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -123,6 +147,23 @@ public class MediaOutputPreferenceControllerTest {
|
|||||||
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager;
|
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager;
|
||||||
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
|
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
|
||||||
|
|
||||||
|
when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mMediaSessionManager);
|
||||||
|
when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
|
||||||
|
when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
|
||||||
|
mPlaybackInfo = new MediaController.PlaybackInfo(
|
||||||
|
MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
|
||||||
|
VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
|
||||||
|
100,
|
||||||
|
10,
|
||||||
|
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
|
||||||
|
null);
|
||||||
|
mPlaybackState = new PlaybackState.Builder()
|
||||||
|
.setState(PlaybackState.STATE_PLAYING, 0, 1)
|
||||||
|
.build();
|
||||||
|
when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
|
||||||
|
when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
|
||||||
|
mMediaControllers.add(mMediaController);
|
||||||
|
|
||||||
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
|
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
|
||||||
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
|
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
|
||||||
when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
|
when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
|
||||||
@@ -226,6 +267,30 @@ public class MediaOutputPreferenceControllerTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_noActiveLocalPlayback_noTitle() {
|
||||||
|
mPlaybackState = new PlaybackState.Builder()
|
||||||
|
.setState(PlaybackState.STATE_NONE, 0, 1)
|
||||||
|
.build();
|
||||||
|
when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
|
||||||
|
mController = new MediaOutputPreferenceController(mContext, TEST_KEY);
|
||||||
|
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertThat(mPreference.getTitle()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_withActiveLocalPlayback_checkTitle() {
|
||||||
|
initPackage();
|
||||||
|
mShadowPackageManager.addPackage(mPackageInfo, mPackageStats);
|
||||||
|
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertThat(mPreference.getTitle()).isEqualTo(
|
||||||
|
mContext.getString(R.string.media_output_label_title, TEST_APPLICATION_LABEL));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void click_launch_outputSwitcherSlice() {
|
public void click_launch_outputSwitcherSlice() {
|
||||||
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
@@ -282,4 +347,16 @@ public class MediaOutputPreferenceControllerTest {
|
|||||||
|
|
||||||
assertThat(mController.findActiveDevice()).isNull();
|
assertThat(mController.findActiveDevice()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initPackage() {
|
||||||
|
mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
|
||||||
|
mAppInfo = new ApplicationInfo();
|
||||||
|
mAppInfo.flags = ApplicationInfo.FLAG_INSTALLED;
|
||||||
|
mAppInfo.packageName = TEST_PACKAGE_NAME;
|
||||||
|
mAppInfo.name = TEST_APPLICATION_LABEL;
|
||||||
|
mPackageInfo = new PackageInfo();
|
||||||
|
mPackageInfo.packageName = TEST_PACKAGE_NAME;
|
||||||
|
mPackageInfo.applicationInfo = mAppInfo;
|
||||||
|
mPackageStats = new PackageStats(TEST_PACKAGE_NAME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user