Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +21 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -379,7 +378,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController if (FeatureFlagUtils.isEnabled( mContext, 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. AudioSharingUtils.postOnMainThread( mContext, Loading Loading @@ -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(); } } Loading Loading @@ -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) && (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, () -> { Loading @@ -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<Integer, Object>[] eventData = AudioSharingUtils.buildAudioSharingDialogEventData( Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java +5 −8 Original line number Diff line number Diff line Loading @@ -215,16 +215,13 @@ public class AudioSharingUtils { @Nullable LocalBluetoothManager localBtManager) { CachedBluetoothDeviceManager deviceManager = localBtManager == null ? null : localBtManager.getCachedDeviceManager(); Map<Integer, List<BluetoothDevice>> groupedConnectedDevices = fetchConnectedDevicesByGroupId(localBtManager); for (List<BluetoothDevice> 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 deviceManager.getCachedDevicesCopy().stream().anyMatch( BluetoothUtils::isActiveMediaDevice); } /** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */ public static AudioSharingDeviceItem buildAudioSharingDeviceItem( Loading tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +48 −17 Original line number Diff line number Diff line Loading @@ -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<Fragment, String> TAG_EQUALS = private static final Correspondence<Fragment, String> 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(); Loading Loading @@ -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); Loading Loading @@ -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<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments(); assertThat(childFragments) .comparingElementsUsing(CLAZZNAME_EQUALS) .containsExactly(AudioSharingConfirmDialogFragment.class.getName()); } @Test Loading Loading @@ -526,8 +545,8 @@ public class AudioSharingSwitchBarControllerTest { List<Fragment> 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); Loading Loading @@ -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(); Loading Loading @@ -706,6 +727,8 @@ 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(); Loading @@ -713,16 +736,24 @@ public class AudioSharingSwitchBarControllerTest { } @Test public void onActiveDeviceChanged_nullActiveDevice_doNothing() { mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO); 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(); verify(mSwitchBar, never()).setEnabled(anyBoolean()); verify(mSwitchBar, never()).setChecked(anyBoolean()); assertThat(mSwitchBar.isChecked()).isFalse(); verify(mSwitchBar).setEnabled(true); } @Test public void onActiveDeviceChanged_notLeaProfile_doNothing() { mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET); public void onActiveDeviceChanged_nullActiveDevice_doNothing() { mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setEnabled(anyBoolean()); verify(mSwitchBar, never()).setChecked(anyBoolean()); Loading Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +21 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -379,7 +378,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController if (FeatureFlagUtils.isEnabled( mContext, 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. AudioSharingUtils.postOnMainThread( mContext, Loading Loading @@ -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(); } } Loading Loading @@ -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) && (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, () -> { Loading @@ -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<Integer, Object>[] eventData = AudioSharingUtils.buildAudioSharingDialogEventData( Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java +5 −8 Original line number Diff line number Diff line Loading @@ -215,16 +215,13 @@ public class AudioSharingUtils { @Nullable LocalBluetoothManager localBtManager) { CachedBluetoothDeviceManager deviceManager = localBtManager == null ? null : localBtManager.getCachedDeviceManager(); Map<Integer, List<BluetoothDevice>> groupedConnectedDevices = fetchConnectedDevicesByGroupId(localBtManager); for (List<BluetoothDevice> 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 deviceManager.getCachedDevicesCopy().stream().anyMatch( BluetoothUtils::isActiveMediaDevice); } /** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */ public static AudioSharingDeviceItem buildAudioSharingDeviceItem( Loading
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +48 −17 Original line number Diff line number Diff line Loading @@ -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<Fragment, String> TAG_EQUALS = private static final Correspondence<Fragment, String> 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(); Loading Loading @@ -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); Loading Loading @@ -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<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments(); assertThat(childFragments) .comparingElementsUsing(CLAZZNAME_EQUALS) .containsExactly(AudioSharingConfirmDialogFragment.class.getName()); } @Test Loading Loading @@ -526,8 +545,8 @@ public class AudioSharingSwitchBarControllerTest { List<Fragment> 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); Loading Loading @@ -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(); Loading Loading @@ -706,6 +727,8 @@ 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(); Loading @@ -713,16 +736,24 @@ public class AudioSharingSwitchBarControllerTest { } @Test public void onActiveDeviceChanged_nullActiveDevice_doNothing() { mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO); 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(); verify(mSwitchBar, never()).setEnabled(anyBoolean()); verify(mSwitchBar, never()).setChecked(anyBoolean()); assertThat(mSwitchBar.isChecked()).isFalse(); verify(mSwitchBar).setEnabled(true); } @Test public void onActiveDeviceChanged_notLeaProfile_doNothing() { mController.onActiveDeviceChanged(mCachedDevice2, BluetoothProfile.HEADSET); public void onActiveDeviceChanged_nullActiveDevice_doNothing() { mController.onActiveDeviceChanged(/* activeDevice= */ null, BluetoothProfile.LE_AUDIO); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setEnabled(anyBoolean()); verify(mSwitchBar, never()).setChecked(anyBoolean()); Loading