Merge "[Audiosharing] Change main toggle enable conditions." into main

This commit is contained in:
Yiyi Shen
2024-09-10 10:55:36 +00:00
committed by Android (Google) Code Review
3 changed files with 76 additions and 35 deletions

View File

@@ -25,7 +25,6 @@ import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant; import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -377,9 +376,9 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
// FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST is always true in // FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST is always true in
// prod. We can turn off the flag for debug purpose. // prod. We can turn off the flag for debug purpose.
if (FeatureFlagUtils.isEnabled( if (FeatureFlagUtils.isEnabled(
mContext, mContext,
FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST) FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)
&& mAssistant.getAllConnectedDevices().isEmpty()) { && hasEmptyConnectedSink()) {
// Pop up dialog to ask users to connect at least one lea buds before audio sharing. // Pop up dialog to ask users to connect at least one lea buds before audio sharing.
AudioSharingUtils.postOnMainThread( AudioSharingUtils.postOnMainThread(
mContext, mContext,
@@ -435,8 +434,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
} }
@Override @Override
public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { public void onActiveDeviceChanged(@Nullable CachedBluetoothDevice activeDevice,
if (activeDevice != null && bluetoothProfile == BluetoothProfile.LE_AUDIO) { int bluetoothProfile) {
if (activeDevice != null) {
Log.d(TAG, "onActiveDeviceChanged: device = "
+ activeDevice.getDevice().getAnonymizedAddress()
+ ", profile = " + bluetoothProfile);
updateSwitch(); updateSwitch();
} }
} }
@@ -536,13 +539,19 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
boolean isBroadcasting = BluetoothUtils.isBroadcasting(mBtManager); boolean isBroadcasting = BluetoothUtils.isBroadcasting(mBtManager);
boolean hasActiveDevice = boolean hasActiveDevice =
AudioSharingUtils.hasActiveConnectedLeadDevice(mBtManager); AudioSharingUtils.hasActiveConnectedLeadDevice(mBtManager);
boolean hasEmptyConnectedDevice = hasEmptyConnectedSink();
boolean isStateReady = boolean isStateReady =
isBluetoothOn() isBluetoothOn()
&& AudioSharingUtils.isAudioSharingProfileReady( && AudioSharingUtils.isAudioSharingProfileReady(
mProfileManager) mProfileManager)
&& (isBroadcasting
// Always enable toggle when no connected sink. We have
// dialog to guide users to connect compatible devices
// for audio sharing.
|| hasEmptyConnectedDevice
// Disable toggle till device gets active after // Disable toggle till device gets active after
// broadcast ends. // broadcast ends.
&& (isBroadcasting || hasActiveDevice); || hasActiveDevice);
AudioSharingUtils.postOnMainThread( AudioSharingUtils.postOnMainThread(
mContext, mContext,
() -> { () -> {
@@ -566,6 +575,10 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled(); return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
} }
private boolean hasEmptyConnectedSink() {
return mAssistant != null && mAssistant.getAllConnectedDevices().isEmpty();
}
private void handleOnBroadcastReady() { private void handleOnBroadcastReady() {
Pair<Integer, Object>[] eventData = Pair<Integer, Object>[] eventData =
AudioSharingUtils.buildAudioSharingDialogEventData( AudioSharingUtils.buildAudioSharingDialogEventData(

View File

@@ -215,15 +215,12 @@ public class AudioSharingUtils {
@Nullable LocalBluetoothManager localBtManager) { @Nullable LocalBluetoothManager localBtManager) {
CachedBluetoothDeviceManager deviceManager = CachedBluetoothDeviceManager deviceManager =
localBtManager == null ? null : localBtManager.getCachedDeviceManager(); localBtManager == null ? null : localBtManager.getCachedDeviceManager();
Map<Integer, List<BluetoothDevice>> groupedConnectedDevices = if (deviceManager == null) {
fetchConnectedDevicesByGroupId(localBtManager); Log.d(TAG, "hasActiveConnectedLeadDevice return false due to null device manager.");
for (List<BluetoothDevice> devices : groupedConnectedDevices.values()) { return false;
CachedBluetoothDevice leadDevice = getLeadDevice(deviceManager, devices);
if (isActiveLeAudioDevice(leadDevice)) {
return true;
}
} }
return false; return deviceManager.getCachedDevicesCopy().stream().anyMatch(
BluetoothUtils::isActiveMediaDevice);
} }
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */ /** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */

View File

@@ -111,10 +111,10 @@ import java.util.concurrent.Executor;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config( @Config(
shadows = { shadows = {
ShadowBluetoothAdapter.class, ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class, ShadowBluetoothUtils.class,
ShadowThreadUtils.class, ShadowThreadUtils.class,
ShadowAlertDialogCompat.class ShadowAlertDialogCompat.class
}) })
public class AudioSharingSwitchBarControllerTest { public class AudioSharingSwitchBarControllerTest {
private static final String TEST_DEVICE_NAME1 = "test1"; private static final String TEST_DEVICE_NAME1 = "test1";
@@ -123,12 +123,13 @@ public class AudioSharingSwitchBarControllerTest {
private static final String TEST_DEVICE_ANONYMIZED_ADDR2 = "XX:XX:02"; private static final String TEST_DEVICE_ANONYMIZED_ADDR2 = "XX:XX:02";
private static final int TEST_DEVICE_GROUP_ID1 = 1; private static final int TEST_DEVICE_GROUP_ID1 = 1;
private static final int TEST_DEVICE_GROUP_ID2 = 2; private static final int TEST_DEVICE_GROUP_ID2 = 2;
private static final Correspondence<Fragment, String> TAG_EQUALS = private static final Correspondence<Fragment, String> CLAZZNAME_EQUALS =
Correspondence.from( Correspondence.from(
(Fragment fragment, String tag) -> (Fragment fragment, String clazzName) ->
fragment instanceof DialogFragment fragment instanceof DialogFragment
&& ((DialogFragment) fragment).getTag() != null && ((DialogFragment) fragment).getClass().getName() != null
&& ((DialogFragment) fragment).getTag().equals(tag), && ((DialogFragment) fragment).getClass().getName().equals(
clazzName),
"is equal to"); "is equal to");
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -343,6 +344,18 @@ public class AudioSharingSwitchBarControllerTest {
assertThat(mSwitchBar.isEnabled()).isTrue(); assertThat(mSwitchBar.isEnabled()).isTrue();
} }
@Test
public void onStart_flagOn_updateSwitch() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(false);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of());
mController.onStart(mLifecycleOwner);
shadowOf(Looper.getMainLooper()).idle();
assertThat(mSwitchBar.isChecked()).isFalse();
assertThat(mSwitchBar.isEnabled()).isTrue();
}
@Test @Test
public void onStop_flagOff_doNothing() { public void onStop_flagOff_doNothing() {
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
@@ -398,15 +411,21 @@ public class AudioSharingSwitchBarControllerTest {
} }
@Test @Test
public void onCheckedChangedToChecked_noConnectedLeaDevices_flagOn_notStartAudioSharing() { public void onCheckedChangedToChecked_noConnectedLeaDevices_flagOn_showDialog() {
FeatureFlagUtils.setEnabled( FeatureFlagUtils.setEnabled(
mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
when(mBtnView.isEnabled()).thenReturn(true); when(mBtnView.isEnabled()).thenReturn(true);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of()); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of());
doNothing().when(mBroadcast).startPrivateBroadcast(); doNothing().when(mBroadcast).startPrivateBroadcast();
mController.onCheckedChanged(mBtnView, /* isChecked= */ true); mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
shadowOf(Looper.getMainLooper()).idle();
assertThat(mSwitchBar.isChecked()).isFalse(); assertThat(mSwitchBar.isChecked()).isFalse();
verify(mBroadcast, never()).startPrivateBroadcast(); verify(mBroadcast, never()).startPrivateBroadcast();
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
assertThat(childFragments)
.comparingElementsUsing(CLAZZNAME_EQUALS)
.containsExactly(AudioSharingConfirmDialogFragment.class.getName());
} }
@Test @Test
@@ -526,8 +545,8 @@ public class AudioSharingSwitchBarControllerTest {
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments(); List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
assertThat(childFragments) assertThat(childFragments)
.comparingElementsUsing(TAG_EQUALS) .comparingElementsUsing(CLAZZNAME_EQUALS)
.containsExactly(AudioSharingDialogFragment.tag()); .containsExactly(AudioSharingDialogFragment.class.getName());
AudioSharingDialogFragment fragment = AudioSharingDialogFragment fragment =
(AudioSharingDialogFragment) Iterables.getOnlyElement(childFragments); (AudioSharingDialogFragment) Iterables.getOnlyElement(childFragments);
@@ -613,6 +632,8 @@ public class AudioSharingSwitchBarControllerTest {
mSwitchBar.setChecked(false); mSwitchBar.setChecked(false);
when(mBroadcast.isEnabled(any())).thenReturn(false); when(mBroadcast.isEnabled(any())).thenReturn(false);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice1, mDevice2)); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice1, mDevice2));
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedDevice1, mCachedDevice2));
mController.mBroadcastCallback.onBroadcastStartFailed(/* reason= */ 1); mController.mBroadcastCallback.onBroadcastStartFailed(/* reason= */ 1);
shadowOf(Looper.getMainLooper()).idle(); shadowOf(Looper.getMainLooper()).idle();
assertThat(mSwitchBar.isChecked()).isFalse(); assertThat(mSwitchBar.isChecked()).isFalse();
@@ -706,12 +727,30 @@ public class AudioSharingSwitchBarControllerTest {
mSwitchBar.setEnabled(false); mSwitchBar.setEnabled(false);
when(mBroadcast.isEnabled(null)).thenReturn(false); when(mBroadcast.isEnabled(null)).thenReturn(false);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedDevice2, mCachedDevice1));
mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.LE_AUDIO); mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.LE_AUDIO);
shadowOf(Looper.getMainLooper()).idle(); shadowOf(Looper.getMainLooper()).idle();
assertThat(mSwitchBar.isChecked()).isFalse(); assertThat(mSwitchBar.isChecked()).isFalse();
verify(mSwitchBar).setEnabled(true); verify(mSwitchBar).setEnabled(true);
} }
@Test
public void onActiveDeviceChanged_a2dpProfile_updateSwitch() {
mSwitchBar.setChecked(true);
mSwitchBar.setEnabled(false);
when(mBroadcast.isEnabled(null)).thenReturn(false);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice1, mDevice2));
when(mCachedDevice2.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(false);
when(mCachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(true);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(
ImmutableList.of(mCachedDevice1, mCachedDevice2));
mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.A2DP);
shadowOf(Looper.getMainLooper()).idle();
assertThat(mSwitchBar.isChecked()).isFalse();
verify(mSwitchBar).setEnabled(true);
}
@Test @Test
public void onActiveDeviceChanged_nullActiveDevice_doNothing() { public void onActiveDeviceChanged_nullActiveDevice_doNothing() {
mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO); mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO);
@@ -720,14 +759,6 @@ public class AudioSharingSwitchBarControllerTest {
verify(mSwitchBar, never()).setChecked(anyBoolean()); verify(mSwitchBar, never()).setChecked(anyBoolean());
} }
@Test
public void onActiveDeviceChanged_notLeaProfile_doNothing() {
mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET);
shadowOf(Looper.getMainLooper()).idle();
verify(mSwitchBar, never()).setEnabled(anyBoolean());
verify(mSwitchBar, never()).setChecked(anyBoolean());
}
@Test @Test
public void testAccessibilityDelegate() { public void testAccessibilityDelegate() {
View view = new View(mContext); View view = new View(mContext);