Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +89 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settings.connecteddevice.audiosharing; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_START_LE_AUDIO_SHARING; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; Loading @@ -27,6 +29,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.FeatureFlagUtils; import android.util.Log; import android.util.Pair; Loading @@ -44,6 +47,7 @@ import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.bluetooth.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.overlay.FeatureFactory; Loading @@ -66,6 +70,7 @@ import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; public class AudioSharingSwitchBarController extends BasePreferenceController implements DefaultLifecycleObserver, Loading Loading @@ -106,6 +111,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>(); @VisibleForTesting IntentFilter mIntentFilter; private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); private AtomicInteger mIntentHandleStage = new AtomicInteger(StartIntentHandleStage.TO_HANDLE.ordinal()); @VisibleForTesting BroadcastReceiver mReceiver = Loading Loading @@ -309,6 +316,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController return; } registerCallbacks(); if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.TO_HANDLE.ordinal(), StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal())) { Log.d(TAG, "onStart: handleStartAudioSharingFromIntent"); handleStartAudioSharingFromIntent(); } } @Override Loading Loading @@ -386,6 +399,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController if (mProfileManager != null) { mProfileManager.removeServiceListener(this); } if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.TO_HANDLE.ordinal(), StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal())) { Log.d(TAG, "onServiceConnected: handleStartAudioSharingFromIntent"); handleStartAudioSharingFromIntent(); } } } Loading Loading @@ -526,7 +545,24 @@ public class AudioSharingSwitchBarController extends BasePreferenceController AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING); mTargetActiveSinks.clear(); if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()) && mDeviceItemsForSharing.size() == 1) { Log.d(TAG, "handleOnBroadcastReady: auto add source to the second device"); AudioSharingUtils.addSourceToTargetSinks( mGroupedConnectedDevices.getOrDefault( mDeviceItemsForSharing.get(0).getGroupId(), ImmutableList.of()), mBtManager); mGroupedConnectedDevices.clear(); mDeviceItemsForSharing.clear(); // TODO: Add metric for auto add by intent return; } } mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()); if (mFragment == null) { Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment."); mGroupedConnectedDevices.clear(); Loading Loading @@ -580,4 +616,50 @@ public class AudioSharingSwitchBarController extends BasePreferenceController return super.onRequestSendAccessibilityEvent(host, view, event); } } private void handleStartAudioSharingFromIntent() { var unused = ThreadUtils.postOnBackgroundThread( () -> { if (mFragment == null || mFragment.getActivity() == null || mFragment.getActivity().getIntent() == null) { Log.d( TAG, "Skip handleStartAudioSharingFromIntent, " + "fragment intent is null"); return; } Intent intent = mFragment.getActivity().getIntent(); Bundle args = intent.getBundleExtra( SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); Boolean shouldStart = args != null && args.getBoolean(EXTRA_START_LE_AUDIO_SHARING, false); if (!shouldStart) { Log.d(TAG, "Skip handleStartAudioSharingFromIntent, arg false"); mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()); return; } if (BluetoothUtils.isBroadcasting(mBtManager)) { Log.d(TAG, "Skip handleStartAudioSharingFromIntent, in broadcast"); mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()); return; } Log.d(TAG, "HandleStartAudioSharingFromIntent, start broadcast"); AudioSharingUtils.postOnMainThread( mContext, () -> mSwitchBar.setChecked(true)); }); } private enum StartIntentHandleStage { TO_HANDLE, HANDLE_AUTO_ADD, HANDLED, } } tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +136 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.settings.connecteddevice.audiosharing; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_START_LE_AUDIO_SHARING; import static com.google.common.truth.Truth.assertThat; Loading @@ -33,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; Loading @@ -47,6 +49,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Looper; import android.platform.test.flag.junit.SetFlagsRule; import android.util.FeatureFlagUtils; Loading @@ -55,14 +58,18 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.widget.CompoundButton; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LifecycleOwner; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.bluetooth.Utils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.testutils.shadow.ShadowThreadUtils; Loading Loading @@ -105,6 +112,7 @@ import java.util.concurrent.Executor; ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class, ShadowThreadUtils.class, ShadowAlertDialogCompat.class }) public class AudioSharingSwitchBarControllerTest { private static final String TEST_DEVICE_NAME1 = "test1"; Loading @@ -129,6 +137,7 @@ public class AudioSharingSwitchBarControllerTest { @Mock private LocalBluetoothLeBroadcast mBroadcast; @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; @Mock private VolumeControlProfile mVolumeControl; @Mock private BluetoothLeBroadcastMetadata mMetadata; @Mock private CompoundButton mBtnView; @Mock private CachedBluetoothDevice mCachedDevice1; @Mock private CachedBluetoothDevice mCachedDevice2; Loading Loading @@ -434,6 +443,7 @@ public class AudioSharingSwitchBarControllerTest { mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); doNothing().when(mBroadcast).startPrivateBroadcast(); mController = new AudioSharingSwitchBarController( Loading Loading @@ -466,6 +476,7 @@ public class AudioSharingSwitchBarControllerTest { when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); verify(mBroadcast).startPrivateBroadcast(); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); Loading Loading @@ -502,6 +513,58 @@ public class AudioSharingSwitchBarControllerTest { 1)); } @Test public void onPlaybackStarted_clickShareBtnOnDialog_addSource() { FeatureFlagUtils.setEnabled( mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); verify(mBroadcast).startPrivateBroadcast(); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false); AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); View btnView = dialog.findViewById(R.id.positive_btn); assertThat(btnView).isNotNull(); btnView.performClick(); shadowMainLooper().idle(); verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); assertThat(dialog.isShowing()).isFalse(); } @Test public void onPlaybackStarted_clickCancelBtnOnDialog_doNothing() { FeatureFlagUtils.setEnabled( mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); verify(mBroadcast).startPrivateBroadcast(); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false); AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); View btnView = dialog.findViewById(R.id.negative_btn); assertThat(btnView).isNotNull(); btnView.performClick(); shadowMainLooper().idle(); verify(mAssistant, never()).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); assertThat(dialog.isShowing()).isFalse(); } @Test public void testBluetoothLeBroadcastCallbacks_updateSwitch() { mOnAudioSharingStateChanged = false; Loading Loading @@ -543,8 +606,7 @@ public class AudioSharingSwitchBarControllerTest { @Test public void testBluetoothLeBroadcastCallbacks_doNothing() { BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, metadata); mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, mMetadata); mController.mBroadcastCallback.onBroadcastUpdated(/* reason= */ 1, /* broadcastId= */ 1); mController.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1); mController.mBroadcastCallback.onPlaybackStopped(/* reason= */ 1, /* broadcastId= */ 1); Loading @@ -556,9 +618,8 @@ public class AudioSharingSwitchBarControllerTest { @Test public void testBluetoothLeBroadcastAssistantCallbacks_logAction() { BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); mController.mBroadcastAssistantCallback.onSourceAddFailed( mDevice1, metadata, /* reason= */ 1); mDevice1, mMetadata, /* reason= */ 1); verify(mFeatureFactory.metricsFeatureProvider) .action( mContext, Loading @@ -569,7 +630,6 @@ public class AudioSharingSwitchBarControllerTest { @Test public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() { BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class); BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); // Do nothing mController.mBroadcastAssistantCallback.onReceiveStateChanged( Loading @@ -588,7 +648,7 @@ public class AudioSharingSwitchBarControllerTest { mDevice1, /* sourceId= */ 1, /* reason= */ 1); mController.mBroadcastAssistantCallback.onSourceModifyFailed( mDevice1, /* sourceId= */ 1, /* reason= */ 1); mController.mBroadcastAssistantCallback.onSourceFound(metadata); mController.mBroadcastAssistantCallback.onSourceFound(mMetadata); mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1); verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider); } Loading @@ -614,4 +674,74 @@ public class AudioSharingSwitchBarControllerTest { .onRequestSendAccessibilityEvent(mSwitchBar, view, event)) .isFalse(); } @Test public void handleStartAudioSharingFromIntent_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); setUpStartSharingIntent(); mController.onStart(mLifecycleOwner); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setChecked(true); } @Test public void handleStartAudioSharingFromIntent_profileNotReady_doNothing() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mAssistant.isProfileReady()).thenReturn(false); setUpStartSharingIntent(); mController.onServiceConnected(); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setChecked(true); } @Test public void handleStartAudioSharingFromIntent_argFalse_doNothing() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStart(mLifecycleOwner); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setChecked(true); } @Test public void handleStartAudioSharingFromIntent_handle() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); setUpStartSharingIntent(); mController.onServiceConnected(); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar).setChecked(true); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); verify(mFeatureFactory.metricsFeatureProvider) .action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING)); verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false); List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments(); assertThat(childFragments).isEmpty(); } private void setUpStartSharingIntent() { Bundle args = new Bundle(); args.putBoolean(EXTRA_START_LE_AUDIO_SHARING, true); Intent intent = new Intent(); intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); Fragment fragment = new Fragment(); FragmentController.of(fragment, intent) .create(/* containerViewId= */ 0, /* bundle= */ null) .start() .resume() .visible() .get(); shadowOf(Looper.getMainLooper()).idle(); mController.init(fragment); } } Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +89 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.settings.connecteddevice.audiosharing; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_START_LE_AUDIO_SHARING; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; Loading @@ -27,6 +29,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.FeatureFlagUtils; import android.util.Log; import android.util.Pair; Loading @@ -44,6 +47,7 @@ import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.bluetooth.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.overlay.FeatureFactory; Loading @@ -66,6 +70,7 @@ import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; public class AudioSharingSwitchBarController extends BasePreferenceController implements DefaultLifecycleObserver, Loading Loading @@ -106,6 +111,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>(); @VisibleForTesting IntentFilter mIntentFilter; private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); private AtomicInteger mIntentHandleStage = new AtomicInteger(StartIntentHandleStage.TO_HANDLE.ordinal()); @VisibleForTesting BroadcastReceiver mReceiver = Loading Loading @@ -309,6 +316,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController return; } registerCallbacks(); if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.TO_HANDLE.ordinal(), StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal())) { Log.d(TAG, "onStart: handleStartAudioSharingFromIntent"); handleStartAudioSharingFromIntent(); } } @Override Loading Loading @@ -386,6 +399,12 @@ public class AudioSharingSwitchBarController extends BasePreferenceController if (mProfileManager != null) { mProfileManager.removeServiceListener(this); } if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.TO_HANDLE.ordinal(), StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal())) { Log.d(TAG, "onServiceConnected: handleStartAudioSharingFromIntent"); handleStartAudioSharingFromIntent(); } } } Loading Loading @@ -526,7 +545,24 @@ public class AudioSharingSwitchBarController extends BasePreferenceController AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING); mTargetActiveSinks.clear(); if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()) && mDeviceItemsForSharing.size() == 1) { Log.d(TAG, "handleOnBroadcastReady: auto add source to the second device"); AudioSharingUtils.addSourceToTargetSinks( mGroupedConnectedDevices.getOrDefault( mDeviceItemsForSharing.get(0).getGroupId(), ImmutableList.of()), mBtManager); mGroupedConnectedDevices.clear(); mDeviceItemsForSharing.clear(); // TODO: Add metric for auto add by intent return; } } mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()); if (mFragment == null) { Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment."); mGroupedConnectedDevices.clear(); Loading Loading @@ -580,4 +616,50 @@ public class AudioSharingSwitchBarController extends BasePreferenceController return super.onRequestSendAccessibilityEvent(host, view, event); } } private void handleStartAudioSharingFromIntent() { var unused = ThreadUtils.postOnBackgroundThread( () -> { if (mFragment == null || mFragment.getActivity() == null || mFragment.getActivity().getIntent() == null) { Log.d( TAG, "Skip handleStartAudioSharingFromIntent, " + "fragment intent is null"); return; } Intent intent = mFragment.getActivity().getIntent(); Bundle args = intent.getBundleExtra( SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); Boolean shouldStart = args != null && args.getBoolean(EXTRA_START_LE_AUDIO_SHARING, false); if (!shouldStart) { Log.d(TAG, "Skip handleStartAudioSharingFromIntent, arg false"); mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()); return; } if (BluetoothUtils.isBroadcasting(mBtManager)) { Log.d(TAG, "Skip handleStartAudioSharingFromIntent, in broadcast"); mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()); return; } Log.d(TAG, "HandleStartAudioSharingFromIntent, start broadcast"); AudioSharingUtils.postOnMainThread( mContext, () -> mSwitchBar.setChecked(true)); }); } private enum StartIntentHandleStage { TO_HANDLE, HANDLE_AUTO_ADD, HANDLED, } }
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +136 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.settings.connecteddevice.audiosharing; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_START_LE_AUDIO_SHARING; import static com.google.common.truth.Truth.assertThat; Loading @@ -33,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; Loading @@ -47,6 +49,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Looper; import android.platform.test.flag.junit.SetFlagsRule; import android.util.FeatureFlagUtils; Loading @@ -55,14 +58,18 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.widget.CompoundButton; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LifecycleOwner; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.bluetooth.Utils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.testutils.shadow.ShadowThreadUtils; Loading Loading @@ -105,6 +112,7 @@ import java.util.concurrent.Executor; ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class, ShadowThreadUtils.class, ShadowAlertDialogCompat.class }) public class AudioSharingSwitchBarControllerTest { private static final String TEST_DEVICE_NAME1 = "test1"; Loading @@ -129,6 +137,7 @@ public class AudioSharingSwitchBarControllerTest { @Mock private LocalBluetoothLeBroadcast mBroadcast; @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; @Mock private VolumeControlProfile mVolumeControl; @Mock private BluetoothLeBroadcastMetadata mMetadata; @Mock private CompoundButton mBtnView; @Mock private CachedBluetoothDevice mCachedDevice1; @Mock private CachedBluetoothDevice mCachedDevice2; Loading Loading @@ -434,6 +443,7 @@ public class AudioSharingSwitchBarControllerTest { mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); doNothing().when(mBroadcast).startPrivateBroadcast(); mController = new AudioSharingSwitchBarController( Loading Loading @@ -466,6 +476,7 @@ public class AudioSharingSwitchBarControllerTest { when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); verify(mBroadcast).startPrivateBroadcast(); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); Loading Loading @@ -502,6 +513,58 @@ public class AudioSharingSwitchBarControllerTest { 1)); } @Test public void onPlaybackStarted_clickShareBtnOnDialog_addSource() { FeatureFlagUtils.setEnabled( mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); verify(mBroadcast).startPrivateBroadcast(); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false); AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); View btnView = dialog.findViewById(R.id.positive_btn); assertThat(btnView).isNotNull(); btnView.performClick(); shadowMainLooper().idle(); verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); assertThat(dialog.isShowing()).isFalse(); } @Test public void onPlaybackStarted_clickCancelBtnOnDialog_doNothing() { FeatureFlagUtils.setEnabled( mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); verify(mBroadcast).startPrivateBroadcast(); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false); AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); View btnView = dialog.findViewById(R.id.negative_btn); assertThat(btnView).isNotNull(); btnView.performClick(); shadowMainLooper().idle(); verify(mAssistant, never()).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); assertThat(dialog.isShowing()).isFalse(); } @Test public void testBluetoothLeBroadcastCallbacks_updateSwitch() { mOnAudioSharingStateChanged = false; Loading Loading @@ -543,8 +606,7 @@ public class AudioSharingSwitchBarControllerTest { @Test public void testBluetoothLeBroadcastCallbacks_doNothing() { BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, metadata); mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, mMetadata); mController.mBroadcastCallback.onBroadcastUpdated(/* reason= */ 1, /* broadcastId= */ 1); mController.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1); mController.mBroadcastCallback.onPlaybackStopped(/* reason= */ 1, /* broadcastId= */ 1); Loading @@ -556,9 +618,8 @@ public class AudioSharingSwitchBarControllerTest { @Test public void testBluetoothLeBroadcastAssistantCallbacks_logAction() { BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); mController.mBroadcastAssistantCallback.onSourceAddFailed( mDevice1, metadata, /* reason= */ 1); mDevice1, mMetadata, /* reason= */ 1); verify(mFeatureFactory.metricsFeatureProvider) .action( mContext, Loading @@ -569,7 +630,6 @@ public class AudioSharingSwitchBarControllerTest { @Test public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() { BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class); BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); // Do nothing mController.mBroadcastAssistantCallback.onReceiveStateChanged( Loading @@ -588,7 +648,7 @@ public class AudioSharingSwitchBarControllerTest { mDevice1, /* sourceId= */ 1, /* reason= */ 1); mController.mBroadcastAssistantCallback.onSourceModifyFailed( mDevice1, /* sourceId= */ 1, /* reason= */ 1); mController.mBroadcastAssistantCallback.onSourceFound(metadata); mController.mBroadcastAssistantCallback.onSourceFound(mMetadata); mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1); verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider); } Loading @@ -614,4 +674,74 @@ public class AudioSharingSwitchBarControllerTest { .onRequestSendAccessibilityEvent(mSwitchBar, view, event)) .isFalse(); } @Test public void handleStartAudioSharingFromIntent_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); setUpStartSharingIntent(); mController.onStart(mLifecycleOwner); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setChecked(true); } @Test public void handleStartAudioSharingFromIntent_profileNotReady_doNothing() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mAssistant.isProfileReady()).thenReturn(false); setUpStartSharingIntent(); mController.onServiceConnected(); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setChecked(true); } @Test public void handleStartAudioSharingFromIntent_argFalse_doNothing() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStart(mLifecycleOwner); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar, never()).setChecked(true); } @Test public void handleStartAudioSharingFromIntent_handle() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mBtnView.isEnabled()).thenReturn(true); when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1)); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); setUpStartSharingIntent(); mController.onServiceConnected(); shadowOf(Looper.getMainLooper()).idle(); verify(mSwitchBar).setChecked(true); doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); mController.mBroadcastCallback.onPlaybackStarted(0, 0); shadowOf(Looper.getMainLooper()).idle(); verify(mFeatureFactory.metricsFeatureProvider) .action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING)); verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false); List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments(); assertThat(childFragments).isEmpty(); } private void setUpStartSharingIntent() { Bundle args = new Bundle(); args.putBoolean(EXTRA_START_LE_AUDIO_SHARING, true); Intent intent = new Intent(); intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); Fragment fragment = new Fragment(); FragmentController.of(fragment, intent) .create(/* containerViewId= */ 0, /* bundle= */ null) .start() .resume() .visible() .get(); shadowOf(Looper.getMainLooper()).idle(); mController.init(fragment); } }