Merge "[Output switcher] Filter disconnected device" into tm-qpr-dev

This commit is contained in:
Shaowei Shen
2022-07-18 09:45:37 +00:00
committed by Android (Google) Code Review
6 changed files with 57 additions and 107 deletions

View File

@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.RoutingSessionInfo; import android.media.RoutingSessionInfo;
import android.os.Build; import android.os.Build;
import android.text.TextUtils; import android.text.TextUtils;
@@ -83,6 +84,7 @@ public class LocalMediaManager implements BluetoothCallback {
private InfoMediaManager mInfoMediaManager; private InfoMediaManager mInfoMediaManager;
private String mPackageName; private String mPackageName;
private MediaDevice mOnTransferBluetoothDevice; private MediaDevice mOnTransferBluetoothDevice;
private AudioManager mAudioManager;
@VisibleForTesting @VisibleForTesting
List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>(); List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -126,6 +128,7 @@ public class LocalMediaManager implements BluetoothCallback {
mPackageName = packageName; mPackageName = packageName;
mLocalBluetoothManager = mLocalBluetoothManager =
LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null); LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null);
mAudioManager = context.getSystemService(AudioManager.class);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mLocalBluetoothManager == null) { if (mLocalBluetoothManager == null) {
Log.e(TAG, "Bluetooth is not supported on this device"); Log.e(TAG, "Bluetooth is not supported on this device");
@@ -148,6 +151,7 @@ public class LocalMediaManager implements BluetoothCallback {
mInfoMediaManager = infoMediaManager; mInfoMediaManager = infoMediaManager;
mPackageName = packageName; mPackageName = packageName;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mAudioManager = context.getSystemService(AudioManager.class);
} }
/** /**
@@ -527,13 +531,16 @@ public class LocalMediaManager implements BluetoothCallback {
synchronized (mMediaDevicesLock) { synchronized (mMediaDevicesLock) {
mMediaDevices.clear(); mMediaDevices.clear();
mMediaDevices.addAll(devices); mMediaDevices.addAll(devices);
// Add disconnected bluetooth devices only when phone output device is available. // Add muting expected bluetooth devices only when phone output device is available.
for (MediaDevice device : devices) { for (MediaDevice device : devices) {
final int type = device.getDeviceType(); final int type = device.getDeviceType();
if (type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE if (type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE || type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE) { || type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE) {
mMediaDevices.addAll(buildDisconnectedBluetoothDevice()); MediaDevice mutingExpectedDevice = getMutingExpectedDevice();
if (mutingExpectedDevice != null) {
mMediaDevices.add(mutingExpectedDevice);
}
break; break;
} }
} }
@@ -552,6 +559,34 @@ public class LocalMediaManager implements BluetoothCallback {
} }
} }
private MediaDevice getMutingExpectedDevice() {
if (mBluetoothAdapter == null
|| mAudioManager.getMutingExpectedDevice() == null) {
Log.w(TAG, "BluetoothAdapter is null or muting expected device not exist");
return null;
}
final List<BluetoothDevice> bluetoothDevices =
mBluetoothAdapter.getMostRecentlyConnectedDevices();
final CachedBluetoothDeviceManager cachedDeviceManager =
mLocalBluetoothManager.getCachedDeviceManager();
for (BluetoothDevice device : bluetoothDevices) {
final CachedBluetoothDevice cachedDevice =
cachedDeviceManager.findDevice(device);
if (isBondedMediaDevice(cachedDevice) && isMutingExpectedDevice(cachedDevice)) {
return new BluetoothMediaDevice(mContext,
cachedDevice,
null, null, mPackageName);
}
}
return null;
}
private boolean isMutingExpectedDevice(CachedBluetoothDevice cachedDevice) {
return mAudioManager.getMutingExpectedDevice() != null
&& cachedDevice.getAddress().equals(
mAudioManager.getMutingExpectedDevice().getAddress());
}
private List<MediaDevice> buildDisconnectedBluetoothDevice() { private List<MediaDevice> buildDisconnectedBluetoothDevice() {
if (mBluetoothAdapter == null) { if (mBluetoothAdapter == null) {
Log.w(TAG, "buildDisconnectedBluetoothDevice() BluetoothAdapter is null"); Log.w(TAG, "buildDisconnectedBluetoothDevice() BluetoothAdapter is null");
@@ -595,6 +630,13 @@ public class LocalMediaManager implements BluetoothCallback {
return new ArrayList<>(mDisconnectedMediaDevices); return new ArrayList<>(mDisconnectedMediaDevices);
} }
private boolean isBondedMediaDevice(CachedBluetoothDevice cachedDevice) {
return cachedDevice != null
&& cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& !cachedDevice.isConnected()
&& isMediaDevice(cachedDevice);
}
private boolean isMediaDevice(CachedBluetoothDevice device) { private boolean isMediaDevice(CachedBluetoothDevice device) {
for (LocalBluetoothProfile profile : device.getConnectableProfiles()) { for (LocalBluetoothProfile profile : device.getConnectableProfiles()) {
if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile || if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile ||

View File

@@ -2297,8 +2297,8 @@
<string name="media_output_dialog_disconnected">(disconnected)</string> <string name="media_output_dialog_disconnected">(disconnected)</string>
<!-- Summary for connecting error message [CHAR LIMIT=NONE] --> <!-- Summary for connecting error message [CHAR LIMIT=NONE] -->
<string name="media_output_dialog_connect_failed">Can\'t switch. Tap to try again.</string> <string name="media_output_dialog_connect_failed">Can\'t switch. Tap to try again.</string>
<!-- Title for pairing item [CHAR LIMIT=60] --> <!-- Title for connecting item [CHAR LIMIT=60] -->
<string name="media_output_dialog_pairing_new">Pair new device</string> <string name="media_output_dialog_pairing_new">Connect a device</string>
<!-- Title for launch app [CHAR LIMIT=60] --> <!-- Title for launch app [CHAR LIMIT=60] -->
<string name="media_output_dialog_launch_app_text">To cast this session, please open the app.</string> <string name="media_output_dialog_launch_app_text">To cast this session, please open the app.</string>
<!-- App name when can't get app name [CHAR LIMIT=60] --> <!-- App name when can't get app name [CHAR LIMIT=60] -->

View File

@@ -60,7 +60,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override @Override
public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) { public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
final int size = mController.getMediaDevices().size(); final int size = mController.getMediaDevices().size();
if (position == size && mController.isZeroMode()) { if (position == size) {
viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */, viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
true /* bottomMargin */); true /* bottomMargin */);
} else if (position < size) { } else if (position < size) {
@@ -75,7 +75,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
final int size = mController.getMediaDevices().size(); final int size = mController.getMediaDevices().size();
if (position == size && mController.isZeroMode()) { if (position == size) {
return -1; return -1;
} else if (position < size) { } else if (position < size) {
return ((List<MediaDevice>) (mController.getMediaDevices())) return ((List<MediaDevice>) (mController.getMediaDevices()))
@@ -88,12 +88,9 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override @Override
public int getItemCount() { public int getItemCount() {
if (mController.isZeroMode()) { // Add extra one for "pair new"
// Add extra one for "pair new" or dynamic group
return mController.getMediaDevices().size() + 1; return mController.getMediaDevices().size() + 1;
} }
return mController.getMediaDevices().size();
}
class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder { class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder {

View File

@@ -16,7 +16,7 @@
package com.android.systemui.media.dialog; package com.android.systemui.media.dialog;
import static android.provider.Settings.ACTION_BLUETOOTH_PAIRING_SETTINGS; import static android.provider.Settings.ACTION_BLUETOOTH_SETTINGS;
import android.annotation.CallbackExecutor; import android.annotation.CallbackExecutor;
import android.app.AlertDialog; import android.app.AlertDialog;
@@ -300,6 +300,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return; return;
} }
try { try {
synchronized (mMediaDevicesLock) {
mMediaDevices.removeIf(MediaDevice::isMutingExpectedDevice);
}
mAudioManager.cancelMuteAwaitConnection(mAudioManager.getMutingExpectedDevice()); mAudioManager.cancelMuteAwaitConnection(mAudioManager.getMutingExpectedDevice());
} catch (Exception e) { } catch (Exception e) {
Log.d(TAG, "Unable to cancel mute await connection"); Log.d(TAG, "Unable to cancel mute await connection");
@@ -711,22 +714,6 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return false; return false;
} }
boolean isZeroMode() {
synchronized (mMediaDevicesLock) {
if (mMediaDevices.size() == 1) {
final MediaDevice device = mMediaDevices.iterator().next();
// Add "pair new" only when local output device exists
final int type = device.getDeviceType();
if (type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE
|| type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE) {
return true;
}
}
return false;
}
}
void launchBluetoothPairing(View view) { void launchBluetoothPairing(View view) {
ActivityLaunchAnimator.Controller controller = ActivityLaunchAnimator.Controller controller =
mDialogLaunchAnimator.createActivityLaunchController(view); mDialogLaunchAnimator.createActivityLaunchController(view);
@@ -736,7 +723,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
} }
Intent launchIntent = Intent launchIntent =
new Intent(ACTION_BLUETOOTH_PAIRING_SETTINGS) new Intent(ACTION_BLUETOOTH_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final Intent deepLinkIntent = final Intent deepLinkIntent =
new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY); new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);

View File

@@ -78,7 +78,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices); when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices);
when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false); when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false);
when(mMediaOutputController.isZeroMode()).thenReturn(false);
when(mMediaOutputController.isTransferring()).thenReturn(false); when(mMediaOutputController.isTransferring()).thenReturn(false);
when(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat); when(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat);
when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat); when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat);
@@ -98,28 +97,12 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
} }
@Test @Test
public void getItemCount_nonZeroMode_isDeviceSize() { public void getItemCount_containExtraOneForPairNew() {
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size());
}
@Test
public void getItemCount_zeroMode_containExtraOneForPairNew() {
when(mMediaOutputController.isZeroMode()).thenReturn(true);
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1); assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size() + 1);
} }
@Test @Test
public void getItemCount_withDynamicGroup_containExtraOneForGroup() { public void onBindViewHolder_bindPairNew_verifyView() {
when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
when(mMediaOutputController.isZeroMode()).thenReturn(false);
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaDevices.size());
}
@Test
public void onBindViewHolder_zeroMode_bindPairNew_verifyView() {
when(mMediaOutputController.isZeroMode()).thenReturn(true);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
@@ -133,7 +116,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test @Test
public void onBindViewHolder_bindGroup_withSessionName_verifyView() { public void onBindViewHolder_bindGroup_withSessionName_verifyView() {
when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices); when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
when(mMediaOutputController.isZeroMode()).thenReturn(false);
when(mMediaOutputController.getSessionName()).thenReturn(TEST_SESSION_NAME); when(mMediaOutputController.getSessionName()).thenReturn(TEST_SESSION_NAME);
mMediaOutputAdapter.getItemCount(); mMediaOutputAdapter.getItemCount();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -148,7 +130,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test @Test
public void onBindViewHolder_bindGroup_noSessionName_verifyView() { public void onBindViewHolder_bindGroup_noSessionName_verifyView() {
when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices); when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices);
when(mMediaOutputController.isZeroMode()).thenReturn(false);
when(mMediaOutputController.getSessionName()).thenReturn(null); when(mMediaOutputController.getSessionName()).thenReturn(null);
mMediaOutputAdapter.getItemCount(); mMediaOutputAdapter.getItemCount();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -257,7 +238,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Test @Test
public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() { public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
when(mMediaOutputController.isZeroMode()).thenReturn(true);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2); mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
mViewHolder.mContainerLayout.performClick(); mViewHolder.mContainerLayout.performClick();

View File

@@ -382,62 +382,6 @@ public class MediaOutputControllerTest extends SysuiTestCase {
assertThat(mMediaOutputController.getActiveRemoteMediaDevices()).isEmpty(); assertThat(mMediaOutputController.getActiveRemoteMediaDevices()).isEmpty();
} }
@Test
public void isZeroMode_onlyFromPhoneOutput_returnTrue() {
// Multiple available devices
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
mMediaDevices.clear();
mMediaDevices.add(mMediaDevice1);
mMediaOutputController.start(mCb);
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
assertThat(mMediaOutputController.isZeroMode()).isTrue();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isTrue();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isTrue();
}
@Test
public void isZeroMode_notFromPhoneOutput_returnFalse() {
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_UNKNOWN);
mMediaDevices.clear();
mMediaDevices.add(mMediaDevice1);
mMediaOutputController.start(mCb);
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_FAST_PAIR_BLUETOOTH_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
}
@Test @Test
public void getGroupMediaDevices_differentDeviceOrder_showingSameOrder() { public void getGroupMediaDevices_differentDeviceOrder_showingSameOrder() {
final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class); final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class);