diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java index 6501084ab7e..2040694c935 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java @@ -25,7 +25,6 @@ import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastAssistant; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastReceiveState; -import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; 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 // prod. We can turn off the flag for debug purpose. if (FeatureFlagUtils.isEnabled( - mContext, - FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST) - && mAssistant.getAllConnectedDevices().isEmpty()) { + mContext, + FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST) + && hasEmptyConnectedSink()) { // Pop up dialog to ask users to connect at least one lea buds before audio sharing. AudioSharingUtils.postOnMainThread( mContext, @@ -435,8 +434,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController } @Override - public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { - if (activeDevice != null && bluetoothProfile == BluetoothProfile.LE_AUDIO) { + public void onActiveDeviceChanged(@Nullable CachedBluetoothDevice activeDevice, + int bluetoothProfile) { + if (activeDevice != null) { + Log.d(TAG, "onActiveDeviceChanged: device = " + + activeDevice.getDevice().getAnonymizedAddress() + + ", profile = " + bluetoothProfile); updateSwitch(); } } @@ -536,13 +539,19 @@ public class AudioSharingSwitchBarController extends BasePreferenceController boolean isBroadcasting = BluetoothUtils.isBroadcasting(mBtManager); boolean hasActiveDevice = AudioSharingUtils.hasActiveConnectedLeadDevice(mBtManager); + boolean hasEmptyConnectedDevice = hasEmptyConnectedSink(); boolean isStateReady = isBluetoothOn() && 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 // broadcast ends. - && (isBroadcasting || hasActiveDevice); + || hasActiveDevice); AudioSharingUtils.postOnMainThread( mContext, () -> { @@ -566,6 +575,10 @@ public class AudioSharingSwitchBarController extends BasePreferenceController return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled(); } + private boolean hasEmptyConnectedSink() { + return mAssistant != null && mAssistant.getAllConnectedDevices().isEmpty(); + } + private void handleOnBroadcastReady() { Pair[] eventData = AudioSharingUtils.buildAudioSharingDialogEventData( diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java index 43256bcdee4..a662809fb78 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java @@ -215,15 +215,12 @@ public class AudioSharingUtils { @Nullable LocalBluetoothManager localBtManager) { CachedBluetoothDeviceManager deviceManager = localBtManager == null ? null : localBtManager.getCachedDeviceManager(); - Map> groupedConnectedDevices = - fetchConnectedDevicesByGroupId(localBtManager); - for (List devices : groupedConnectedDevices.values()) { - CachedBluetoothDevice leadDevice = getLeadDevice(deviceManager, devices); - if (isActiveLeAudioDevice(leadDevice)) { - return true; - } + if (deviceManager == null) { + Log.d(TAG, "hasActiveConnectedLeadDevice return false due to null device manager."); + return false; } - return false; + return deviceManager.getCachedDevicesCopy().stream().anyMatch( + BluetoothUtils::isActiveMediaDevice); } /** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */ diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java index d1533c9703b..354c5c7f08e 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java @@ -111,10 +111,10 @@ import java.util.concurrent.Executor; @RunWith(RobolectricTestRunner.class) @Config( shadows = { - ShadowBluetoothAdapter.class, - ShadowBluetoothUtils.class, - ShadowThreadUtils.class, - ShadowAlertDialogCompat.class + ShadowBluetoothAdapter.class, + ShadowBluetoothUtils.class, + ShadowThreadUtils.class, + ShadowAlertDialogCompat.class }) public class AudioSharingSwitchBarControllerTest { 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 int TEST_DEVICE_GROUP_ID1 = 1; private static final int TEST_DEVICE_GROUP_ID2 = 2; - private static final Correspondence TAG_EQUALS = + private static final Correspondence CLAZZNAME_EQUALS = Correspondence.from( - (Fragment fragment, String tag) -> + (Fragment fragment, String clazzName) -> fragment instanceof DialogFragment - && ((DialogFragment) fragment).getTag() != null - && ((DialogFragment) fragment).getTag().equals(tag), + && ((DialogFragment) fragment).getClass().getName() != null + && ((DialogFragment) fragment).getClass().getName().equals( + clazzName), "is equal to"); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -343,6 +344,18 @@ public class AudioSharingSwitchBarControllerTest { 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 public void onStop_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); @@ -398,15 +411,21 @@ public class AudioSharingSwitchBarControllerTest { } @Test - public void onCheckedChangedToChecked_noConnectedLeaDevices_flagOn_notStartAudioSharing() { + public void onCheckedChangedToChecked_noConnectedLeaDevices_flagOn_showDialog() { FeatureFlagUtils.setEnabled( mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of()); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mSwitchBar.isChecked()).isFalse(); verify(mBroadcast, never()).startPrivateBroadcast(); + List childFragments = mParentFragment.getChildFragmentManager().getFragments(); + assertThat(childFragments) + .comparingElementsUsing(CLAZZNAME_EQUALS) + .containsExactly(AudioSharingConfirmDialogFragment.class.getName()); } @Test @@ -526,8 +545,8 @@ public class AudioSharingSwitchBarControllerTest { List childFragments = mParentFragment.getChildFragmentManager().getFragments(); assertThat(childFragments) - .comparingElementsUsing(TAG_EQUALS) - .containsExactly(AudioSharingDialogFragment.tag()); + .comparingElementsUsing(CLAZZNAME_EQUALS) + .containsExactly(AudioSharingDialogFragment.class.getName()); AudioSharingDialogFragment fragment = (AudioSharingDialogFragment) Iterables.getOnlyElement(childFragments); @@ -613,6 +632,8 @@ public class AudioSharingSwitchBarControllerTest { mSwitchBar.setChecked(false); when(mBroadcast.isEnabled(any())).thenReturn(false); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice1, mDevice2)); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedDevice1, mCachedDevice2)); mController.mBroadcastCallback.onBroadcastStartFailed(/* reason= */ 1); shadowOf(Looper.getMainLooper()).idle(); assertThat(mSwitchBar.isChecked()).isFalse(); @@ -706,12 +727,30 @@ public class AudioSharingSwitchBarControllerTest { mSwitchBar.setEnabled(false); when(mBroadcast.isEnabled(null)).thenReturn(false); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); + when(mDeviceManager.getCachedDevicesCopy()).thenReturn( + ImmutableList.of(mCachedDevice2, mCachedDevice1)); mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.LE_AUDIO); shadowOf(Looper.getMainLooper()).idle(); assertThat(mSwitchBar.isChecked()).isFalse(); 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 public void onActiveDeviceChanged_nullActiveDevice_doNothing() { mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO); @@ -720,14 +759,6 @@ public class AudioSharingSwitchBarControllerTest { 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 public void testAccessibilityDelegate() { View view = new View(mContext);