From 2c6b9bb3640a6bbdadaae6f399c53ff10579f5a5 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Thu, 13 Jun 2024 18:29:23 +0800 Subject: [PATCH] [Audiosharing] Increase audio sharing test coverage Bug: 345686602 Test: atest Change-Id: Iec196fc884c3b7ddd580eb8dd13b445d59e3b1b7 --- ...oSharingCallAudioPreferenceController.java | 10 +- ...udioSharingDevicePreferenceController.java | 11 +- ...dioSharingDeviceVolumeGroupController.java | 18 +- .../AudioSharingDialogFactory.java | 2 + .../AudioSharingDialogHandler.java | 4 +- .../AudioSharingDisconnectDialogFragment.java | 10 +- .../AudioSharingJoinDialogFragment.java | 10 +- .../AudioSharingSwitchBarController.java | 4 +- ...ringCallAudioPreferenceControllerTest.java | 98 +++++++++-- ...SharingDevicePreferenceControllerTest.java | 91 ++++++++-- ...SharingDeviceVolumeControlUpdaterTest.java | 66 +++++++- ...haringDeviceVolumeGroupControllerTest.java | 115 +++++++++++-- .../AudioSharingDialogHandlerTest.java | 158 ++++++++++++++++-- .../AudioSharingSwitchBarControllerTest.java | 81 +++++++-- 14 files changed, 577 insertions(+), 101 deletions(-) diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java index b623ba85b15..6ba7183e897 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java @@ -72,7 +72,7 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP private static final String PREF_KEY = "calls_and_alarms"; @VisibleForTesting - protected enum ChangeCallAudioType { + enum ChangeCallAudioType { UNKNOWN, CONNECTED_EARLIER, CONNECTED_LATER @@ -90,7 +90,9 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP Map> mGroupedConnectedDevices = new HashMap<>(); private List mDeviceItemsInSharingSession = new ArrayList<>(); private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); - private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = + + @VisibleForTesting + final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = new BluetoothLeBroadcastAssistant.Callback() { @Override public void onSearchStarted(int reason) {} @@ -276,7 +278,7 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP /** Test only: set callback registration status in tests. */ @VisibleForTesting - public void setCallbacksRegistered(boolean registered) { + void setCallbacksRegistered(boolean registered) { mCallbacksRegistered.set(registered); } @@ -385,7 +387,7 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP } @VisibleForTesting - protected void logCallAudioDeviceChange(int currentGroupId, CachedBluetoothDevice target) { + void logCallAudioDeviceChange(int currentGroupId, CachedBluetoothDevice target) { var unused = ThreadUtils.postOnBackgroundThread( () -> { diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java index 51a8e117522..b932a7e28ef 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java @@ -87,7 +87,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro @Nullable private AudioSharingDialogHandler mDialogHandler; private AtomicBoolean mIntentHandled = new AtomicBoolean(false); - private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = + @VisibleForTesting + BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = new BluetoothLeBroadcastAssistant.Callback() { @Override public void onSearchStarted(int reason) {} @@ -368,23 +369,23 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro } @VisibleForTesting - public void setBluetoothDeviceUpdater(@Nullable BluetoothDeviceUpdater bluetoothDeviceUpdater) { + void setBluetoothDeviceUpdater(@Nullable BluetoothDeviceUpdater bluetoothDeviceUpdater) { mBluetoothDeviceUpdater = bluetoothDeviceUpdater; } @VisibleForTesting - public void setDialogHandler(@Nullable AudioSharingDialogHandler dialogHandler) { + void setDialogHandler(@Nullable AudioSharingDialogHandler dialogHandler) { mDialogHandler = dialogHandler; } @VisibleForTesting - public void setHostFragment(@Nullable DashboardFragment fragment) { + void setHostFragment(@Nullable DashboardFragment fragment) { mFragment = fragment; } /** Test only: set intent handle state for test. */ @VisibleForTesting - public void setIntentHandled(boolean handled) { + void setIntentHandled(boolean handled) { mIntentHandled.set(handled); } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java index 4a067ace2f2..ee2ba7bb2e3 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java @@ -79,12 +79,9 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre private Map mValueMap = new HashMap(); private AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); - private BluetoothVolumeControl.Callback mVolumeControlCallback = + @VisibleForTesting + BluetoothVolumeControl.Callback mVolumeControlCallback = new BluetoothVolumeControl.Callback() { - @Override - public void onVolumeOffsetChanged( - @NonNull BluetoothDevice device, int volumeOffset) {} - @Override public void onDeviceVolumeChanged( @NonNull BluetoothDevice device, @@ -117,7 +114,8 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre } }; - private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = + @VisibleForTesting + BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = new BluetoothLeBroadcastAssistant.Callback() { @Override public void onSearchStarted(int reason) {} @@ -323,26 +321,26 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre } @VisibleForTesting - public void setDeviceUpdater(@Nullable AudioSharingDeviceVolumeControlUpdater updater) { + void setDeviceUpdater(@Nullable AudioSharingDeviceVolumeControlUpdater updater) { mBluetoothDeviceUpdater = updater; } /** Test only: set callback registration status in tests. */ @VisibleForTesting - public void setCallbacksRegistered(boolean registered) { + void setCallbacksRegistered(boolean registered) { mCallbacksRegistered.set(registered); } /** Test only: set volume map in tests. */ @VisibleForTesting - public void setVolumeMap(@Nullable Map map) { + void setVolumeMap(@Nullable Map map) { mValueMap.clear(); mValueMap.putAll(map); } /** Test only: set value for private preferenceGroup in tests. */ @VisibleForTesting - public void setPreferenceGroup(@Nullable PreferenceGroup group) { + void setPreferenceGroup(@Nullable PreferenceGroup group) { mPreferenceGroup = group; mPreference = group; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java index 165beae9be2..2ee286d4b0e 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogFactory.java @@ -345,4 +345,6 @@ public class AudioSharingDialogFactory { return dialog; } } + + private AudioSharingDialogFactory() {} } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java index 5458a9f259b..8d69cf6232c 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandler.java @@ -28,6 +28,7 @@ import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; @@ -61,7 +62,8 @@ public class AudioSharingDialogHandler { private final MetricsFeatureProvider mMetricsFeatureProvider; private List mTargetSinks = new ArrayList<>(); - private final BluetoothLeBroadcast.Callback mBroadcastCallback = + @VisibleForTesting + final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override public void onBroadcastStarted(int reason, int broadcastId) { diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java index 5f6d84a1929..dcd8a3be19a 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java @@ -145,9 +145,17 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag return sNewDevice; } + /** Test only: get the {@link DialogEventListener} passed to the dialog. */ + @VisibleForTesting + @Nullable + DialogEventListener getListener() { + return sListener; + } + /** Test only: get the event data passed to the dialog. */ @VisibleForTesting - protected @NonNull Pair[] getEventData() { + @NonNull + Pair[] getEventData() { return sEventData; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java index 7eebbcb2156..ec669bf3ac0 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java @@ -110,9 +110,17 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment { return sNewDevice; } + /** Test only: get the {@link DialogEventListener} passed to the dialog. */ + @VisibleForTesting + @Nullable + DialogEventListener getListener() { + return sListener; + } + /** Test only: get the event data passed to the dialog. */ @VisibleForTesting - protected @NonNull Pair[] getEventData() { + @NonNull + Pair[] getEventData() { return sEventData; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java index 5022579ce65..89d2c953a57 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java @@ -117,7 +117,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController }; @VisibleForTesting - protected final BluetoothLeBroadcast.Callback mBroadcastCallback = + final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override public void onBroadcastStarted(int reason, int broadcastId) { @@ -392,7 +392,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController /** Test only: set callback registration status in tests. */ @VisibleForTesting - public void setCallbacksRegistered(boolean registered) { + void setCallbacksRegistered(boolean registered) { mCallbacksRegistered.set(registered); } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java index af817d2987d..aba0a799068 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java @@ -25,7 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -35,6 +35,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; @@ -130,6 +131,7 @@ public class AudioSharingCallAudioPreferenceControllerTest { @Mock private CachedBluetoothDevice mCachedDevice2; @Mock private CachedBluetoothDevice mCachedDevice3; @Mock private BluetoothLeBroadcastReceiveState mState; + @Mock private BluetoothLeBroadcastMetadata mSource; @Mock private ContentResolver mContentResolver; private AudioSharingCallAudioPreferenceController mController; @Spy private ContentObserver mContentObserver; @@ -183,13 +185,13 @@ public class AudioSharingCallAudioPreferenceControllerTest { public void onStart_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStart(mLifecycleOwner); - verify(mBtEventManager, times(0)).registerCallback(mController); - verify(mContentResolver, times(0)) + verify(mBtEventManager, never()).registerCallback(mController); + verify(mContentResolver, never()) .registerContentObserver( Settings.Secure.getUriFor(SETTINGS_KEY_FALLBACK_DEVICE_GROUP_ID), false, mContentObserver); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .registerServiceCallBack(any(), any(BluetoothLeBroadcastAssistant.Callback.class)); } @@ -212,9 +214,9 @@ public class AudioSharingCallAudioPreferenceControllerTest { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.setCallbacksRegistered(true); mController.onStop(mLifecycleOwner); - verify(mBtEventManager, times(0)).unregisterCallback(mController); - verify(mContentResolver, times(0)).unregisterContentObserver(mContentObserver); - verify(mAssistant, times(0)) + verify(mBtEventManager, never()).unregisterCallback(mController); + verify(mContentResolver, never()).unregisterContentObserver(mContentObserver); + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); } @@ -223,9 +225,9 @@ public class AudioSharingCallAudioPreferenceControllerTest { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.setCallbacksRegistered(false); mController.onStop(mLifecycleOwner); - verify(mBtEventManager, times(0)).unregisterCallback(mController); - verify(mContentResolver, times(0)).unregisterContentObserver(mContentObserver); - verify(mAssistant, times(0)) + verify(mBtEventManager, never()).unregisterCallback(mController); + verify(mContentResolver, never()).unregisterContentObserver(mContentObserver); + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); } @@ -500,4 +502,80 @@ public class AudioSharingCallAudioPreferenceControllerTest { AudioSharingCallAudioPreferenceController.ChangeCallAudioType.UNKNOWN .ordinal()); } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_updateSummary() { + when(mCachedDevice1.getGroupId()).thenReturn(TEST_DEVICE_GROUP_ID1); + when(mCachedDevice1.getDevice()).thenReturn(mDevice1); + when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1); + when(mCacheManager.findDevice(mDevice1)).thenReturn(mCachedDevice1); + Settings.Secure.putInt( + mContentResolver, TEST_SETTINGS_KEY, BluetoothCsipSetCoordinator.GROUP_ID_INVALID); + when(mBroadcast.isEnabled(any())).thenReturn(true); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(ImmutableList.of()); + mController.displayPreference(mScreen); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mPreference.getSummary().toString()).isEmpty(); + + // onReceiveStateChanged will update summary + Settings.Secure.putInt(mContentResolver, TEST_SETTINGS_KEY, TEST_DEVICE_GROUP_ID1); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(ImmutableList.of(mDevice1)); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState)); + mController.mBroadcastAssistantCallback.onReceiveStateChanged( + mDevice1, /* sourceId= */ 1, mState); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mPreference.getSummary().toString()) + .isEqualTo( + mContext.getString( + R.string.audio_sharing_call_audio_description, TEST_DEVICE_NAME1)); + } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() { + when(mCachedDevice1.getGroupId()).thenReturn(TEST_DEVICE_GROUP_ID1); + when(mCachedDevice1.getDevice()).thenReturn(mDevice1); + when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1); + when(mCacheManager.findDevice(mDevice1)).thenReturn(mCachedDevice1); + Settings.Secure.putInt( + mContentResolver, TEST_SETTINGS_KEY, BluetoothCsipSetCoordinator.GROUP_ID_INVALID); + when(mBroadcast.isEnabled(any())).thenReturn(true); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(ImmutableList.of()); + mController.displayPreference(mScreen); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mPreference.getSummary().toString()).isEmpty(); + + Settings.Secure.putInt(mContentResolver, TEST_SETTINGS_KEY, TEST_DEVICE_GROUP_ID1); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(ImmutableList.of(mDevice1)); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState)); + mController.mBroadcastAssistantCallback.onSearchStarted(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStartFailed(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStopped(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStopFailed(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceAdded( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceAddFailed( + mDevice1, mSource, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceRemoved( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceRemoveFailed( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceModified( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceModifyFailed( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceFound(mSource); + mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + + // Above callbacks won't update summary. + assertThat(mPreference.getSummary().toString()).isEmpty(); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java index 14bca0840d0..eb29b50bb87 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -35,6 +36,8 @@ import static org.robolectric.Shadows.shadowOf; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.content.Context; @@ -85,6 +88,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executor; @RunWith(RobolectricTestRunner.class) @@ -113,6 +118,8 @@ public class AudioSharingDevicePreferenceControllerTest { @Mock private LocalBluetoothLeBroadcast mBroadcast; @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; @Mock private VolumeControlProfile mVolumeControl; + @Mock private BluetoothLeBroadcastReceiveState mState; + @Mock private BluetoothLeBroadcastMetadata mSource; @Mock private PreferenceScreen mScreen; @Mock private AudioSharingDialogHandler mDialogHandler; @Mock private DashboardFragment mFragment; @@ -177,13 +184,13 @@ public class AudioSharingDevicePreferenceControllerTest { public void onStart_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStart(mLifecycleOwner); - verify(mEventManager, times(0)).registerCallback(any(BluetoothCallback.class)); - verify(mDialogHandler, times(0)).registerCallbacks(any(Executor.class)); - verify(mAssistant, times(0)) + verify(mEventManager, never()).registerCallback(any(BluetoothCallback.class)); + verify(mDialogHandler, never()).registerCallbacks(any(Executor.class)); + verify(mAssistant, never()) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mBluetoothDeviceUpdater, times(0)).registerCallback(); - verify(mBluetoothDeviceUpdater, times(0)).refreshPreference(); + verify(mBluetoothDeviceUpdater, never()).registerCallback(); + verify(mBluetoothDeviceUpdater, never()).refreshPreference(); } @Test @@ -203,11 +210,11 @@ public class AudioSharingDevicePreferenceControllerTest { public void onStop_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStop(mLifecycleOwner); - verify(mEventManager, times(0)).unregisterCallback(any(BluetoothCallback.class)); - verify(mDialogHandler, times(0)).unregisterCallbacks(); - verify(mAssistant, times(0)) + verify(mEventManager, never()).unregisterCallback(any(BluetoothCallback.class)); + verify(mDialogHandler, never()).unregisterCallbacks(); + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mBluetoothDeviceUpdater, times(0)).unregisterCallback(); + verify(mBluetoothDeviceUpdater, never()).unregisterCallback(); } @Test @@ -227,7 +234,7 @@ public class AudioSharingDevicePreferenceControllerTest { mController.displayPreference(mScreen); assertThat(mPreferenceGroup.isVisible()).isFalse(); assertThat(mAudioSharingPreference.isVisible()).isFalse(); - verify(mBluetoothDeviceUpdater, times(0)).forceUpdate(); + verify(mBluetoothDeviceUpdater, never()).forceUpdate(); } @Test @@ -401,8 +408,8 @@ public class AudioSharingDevicePreferenceControllerTest { doReturn(intent).when(mActivity).getIntent(); mController.displayPreference(mScreen); - verify(mDeviceManager, times(0)).findDevice(any(BluetoothDevice.class)); - verify(mDialogHandler, times(0)) + verify(mDeviceManager, never()).findDevice(any(BluetoothDevice.class)); + verify(mDialogHandler, never()) .handleDeviceConnected(any(CachedBluetoothDevice.class), anyBoolean()); } @@ -418,8 +425,8 @@ public class AudioSharingDevicePreferenceControllerTest { when(mDevice.isConnected()).thenReturn(false); mController.displayPreference(mScreen); - verify(mDeviceManager, times(0)).findDevice(any(BluetoothDevice.class)); - verify(mDialogHandler, times(0)) + verify(mDeviceManager, never()).findDevice(any(BluetoothDevice.class)); + verify(mDialogHandler, never()) .handleDeviceConnected(any(CachedBluetoothDevice.class), anyBoolean()); } @@ -436,8 +443,8 @@ public class AudioSharingDevicePreferenceControllerTest { mController.setIntentHandled(true); mController.displayPreference(mScreen); - verify(mDeviceManager, times(0)).findDevice(any(BluetoothDevice.class)); - verify(mDialogHandler, times(0)) + verify(mDeviceManager, never()).findDevice(any(BluetoothDevice.class)); + verify(mDialogHandler, never()) .handleDeviceConnected(any(CachedBluetoothDevice.class), anyBoolean()); } @@ -484,4 +491,56 @@ public class AudioSharingDevicePreferenceControllerTest { verify(mDialogHandler).handleDeviceConnected(mCachedDevice, true); } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_updateGroup() { + // onReceiveStateChanged with unconnected state will do nothing + when(mState.getBisSyncState()).thenReturn(new ArrayList<>()); + mController.mBroadcastAssistantCallback.onReceiveStateChanged( + mDevice, /* sourceId= */ 1, mState); + shadowOf(Looper.getMainLooper()).idle(); + verify(mBluetoothDeviceUpdater, never()).forceUpdate(); + verify(mDialogHandler, never()).closeOpeningDialogsForLeaDevice(mCachedDevice); + + // onReceiveStateChanged with connected state will update group preference and handle + // stale dialogs + List bisSyncState = new ArrayList<>(); + bisSyncState.add(1L); + when(mState.getBisSyncState()).thenReturn(bisSyncState); + mController.mBroadcastAssistantCallback.onReceiveStateChanged( + mDevice, /* sourceId= */ 1, mState); + shadowOf(Looper.getMainLooper()).idle(); + verify(mBluetoothDeviceUpdater).forceUpdate(); + verify(mDialogHandler).closeOpeningDialogsForLeaDevice(mCachedDevice); + + // onSourceRemoved will update group preference + mController.mBroadcastAssistantCallback.onSourceRemoved( + mDevice, /* sourceId= */ 1, /* reason= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + verify(mBluetoothDeviceUpdater, times(2)).forceUpdate(); + } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() { + mController.mBroadcastAssistantCallback.onSearchStarted(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStartFailed(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStopped(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStopFailed(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceAdded( + mDevice, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceAddFailed( + mDevice, mSource, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceRemoveFailed( + mDevice, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceModified( + mDevice, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceModifyFailed( + mDevice, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceFound(mSource); + mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + + // Above callbacks won't update group preference + verify(mBluetoothDeviceUpdater, never()).forceUpdate(); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java index 7a21f02f676..65a0492cf5d 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; @@ -41,6 +42,7 @@ import android.widget.SeekBar; import androidx.preference.Preference; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.testutils.FakeFeatureFactory; @@ -80,6 +82,9 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { private static final String TEST_SETTINGS_KEY = "bluetooth_le_broadcast_fallback_active_group_id"; private static final int TEST_DEVICE_GROUP_ID = 1; + private static final int TEST_VOLUME_VALUE = 255; + private static final int TEST_MAX_STREAM_VALUE = 10; + private static final int TEST_MIN_STREAM_VALUE = 0; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -249,10 +254,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { (AudioSharingDeviceVolumePreference) captor.getValue(); SeekBar seekBar = mock(SeekBar.class); - when(seekBar.getProgress()).thenReturn(255); + when(seekBar.getProgress()).thenReturn(TEST_VOLUME_VALUE); preference.onStopTrackingTouch(seekBar); - verify(mVolumeControl).setDeviceVolume(mBluetoothDevice, 255, true); + verify(mVolumeControl) + .setDeviceVolume(mBluetoothDevice, TEST_VOLUME_VALUE, /* isGroupOp= */ true); verifyNoInteractions(mAudioManager); verify(mFeatureFactory.metricsFeatureProvider) .action( @@ -273,14 +279,17 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { Settings.Secure.putInt( mContext.getContentResolver(), TEST_SETTINGS_KEY, TEST_DEVICE_GROUP_ID); - when(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)).thenReturn(10); - when(mAudioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC)).thenReturn(0); + when(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) + .thenReturn(TEST_MAX_STREAM_VALUE); + when(mAudioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC)) + .thenReturn(TEST_MIN_STREAM_VALUE); SeekBar seekBar = mock(SeekBar.class); - when(seekBar.getProgress()).thenReturn(255); + when(seekBar.getProgress()).thenReturn(TEST_VOLUME_VALUE); preference.onStopTrackingTouch(seekBar); verifyNoInteractions(mVolumeControl); - verify(mAudioManager).setStreamVolume(AudioManager.STREAM_MUSIC, 10, 0); + verify(mAudioManager) + .setStreamVolume(AudioManager.STREAM_MUSIC, TEST_MAX_STREAM_VALUE, /* flags= */ 0); verify(mFeatureFactory.metricsFeatureProvider) .action( mContext, @@ -288,6 +297,22 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { /* isPrimary= */ true); } + @Test + public void testOnSeekBarChangeListener_doNothing() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof AudioSharingDeviceVolumePreference).isTrue(); + AudioSharingDeviceVolumePreference preference = + (AudioSharingDeviceVolumePreference) captor.getValue(); + SeekBar seekBar = mock(SeekBar.class); + preference.onProgressChanged(seekBar, TEST_VOLUME_VALUE, /* fromUser= */ false); + + verifyNoInteractions(mAudioManager); + verifyNoInteractions(mVolumeControl); + } + @Test public void getLogTag_returnsCorrectTag() { assertThat(mDeviceUpdater.getLogTag()).isEqualTo(TAG); @@ -298,6 +323,35 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { assertThat(mDeviceUpdater.getPreferenceKey()).isEqualTo(PREF_KEY); } + @Test + public void addPreferenceWithSortType_doNothing() { + mDeviceUpdater.addPreference( + mCachedBluetoothDevice, BluetoothDevicePreference.SortType.TYPE_DEFAULT); + // Verify AudioSharingDeviceVolumeControlUpdater overrides BluetoothDeviceUpdater and won't + // trigger add preference. + verifyNoInteractions(mDevicePreferenceCallback); + } + + @Test + public void launchDeviceDetails_doNothing() { + Preference preference = mock(Preference.class); + mDeviceUpdater.launchDeviceDetails(preference); + // Verify AudioSharingDeviceVolumeControlUpdater overrides BluetoothDeviceUpdater and won't + // launch device details + verifyNoInteractions(preference); + } + + @Test + public void refreshPreference_doNothing() { + setupPreferenceMapWithDevice(); + verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class)); + when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(ImmutableList.of()); + mDeviceUpdater.refreshPreference(); + // Verify AudioSharingDeviceVolumeControlUpdater overrides BluetoothDeviceUpdater and won't + // refresh preference map + verify(mDevicePreferenceCallback, never()).onDeviceRemoved(any(Preference.class)); + } + private void setupPreferenceMapWithDevice() { // Add device to preferenceMap when(mBroadcast.isEnabled(null)).thenReturn(true); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java index 7c8709cac18..d5dfb50fd7b 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -34,6 +35,8 @@ import static org.robolectric.Shadows.shadowOf; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothVolumeControl; import android.content.ContentResolver; @@ -81,6 +84,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executor; @RunWith(RobolectricTestRunner.class) @@ -114,6 +119,8 @@ public class AudioSharingDeviceVolumeGroupControllerTest { @Mock private LocalBluetoothProfileManager mProfileManager; @Mock private LocalBluetoothLeBroadcast mBroadcast; @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; + @Mock private BluetoothLeBroadcastReceiveState mState; + @Mock private BluetoothLeBroadcastMetadata mSource; @Mock private AudioSharingDeviceVolumeControlUpdater mDeviceUpdater; @Mock private VolumeControlProfile mVolumeControl; @Mock private PreferenceScreen mScreen; @@ -164,6 +171,7 @@ public class AudioSharingDeviceVolumeGroupControllerTest { doReturn(TEST_DEVICE_GROUP_ID1).when(mCachedDevice1).getGroupId(); doReturn(mDevice1).when(mCachedDevice1).getDevice(); doReturn(ImmutableSet.of()).when(mCachedDevice1).getMemberDevice(); + when(mCachedDeviceManager.findDevice(mDevice1)).thenReturn(mCachedDevice1); when(mPreference1.getCachedDevice()).thenReturn(mCachedDevice1); doReturn(TEST_DEVICE_NAME2).when(mCachedDevice2).getName(); doReturn(TEST_DEVICE_GROUP_ID2).when(mCachedDevice2).getGroupId(); @@ -185,13 +193,13 @@ public class AudioSharingDeviceVolumeGroupControllerTest { public void onStart_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStart(mLifecycleOwner); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mDeviceUpdater, times(0)).registerCallback(); - verify(mVolumeControl, times(0)) + verify(mDeviceUpdater, never()).registerCallback(); + verify(mVolumeControl, never()) .registerCallback(any(Executor.class), any(BluetoothVolumeControl.Callback.class)); - verify(mContentResolver, times(0)) + verify(mContentResolver, never()) .registerContentObserver( Settings.Secure.getUriFor(SETTINGS_KEY_FALLBACK_DEVICE_GROUP_ID), false, @@ -215,16 +223,33 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mContentObserver); } + @Test + public void onAudioSharingProfilesConnected_flagOn_registerCallbacks() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + mController.onAudioSharingProfilesConnected(); + verify(mAssistant) + .registerServiceCallBack( + any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); + verify(mDeviceUpdater).registerCallback(); + verify(mVolumeControl) + .registerCallback(any(Executor.class), any(BluetoothVolumeControl.Callback.class)); + verify(mContentResolver) + .registerContentObserver( + Settings.Secure.getUriFor(SETTINGS_KEY_FALLBACK_DEVICE_GROUP_ID), + false, + mContentObserver); + } + @Test public void onStop_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStop(mLifecycleOwner); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mDeviceUpdater, times(0)).unregisterCallback(); - verify(mVolumeControl, times(0)) + verify(mDeviceUpdater, never()).unregisterCallback(); + verify(mVolumeControl, never()) .unregisterCallback(any(BluetoothVolumeControl.Callback.class)); - verify(mContentResolver, times(0)).unregisterContentObserver(mContentObserver); + verify(mContentResolver, never()).unregisterContentObserver(mContentObserver); } @Test @@ -232,12 +257,12 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.setCallbacksRegistered(false); mController.onStop(mLifecycleOwner); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mDeviceUpdater, times(0)).unregisterCallback(); - verify(mVolumeControl, times(0)) + verify(mDeviceUpdater, never()).unregisterCallback(); + verify(mVolumeControl, never()) .unregisterCallback(any(BluetoothVolumeControl.Callback.class)); - verify(mContentResolver, times(0)).unregisterContentObserver(mContentObserver); + verify(mContentResolver, never()).unregisterContentObserver(mContentObserver); } @Test @@ -257,7 +282,7 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.displayPreference(mScreen); assertThat(mPreferenceGroup.isVisible()).isFalse(); - verify(mDeviceUpdater, times(0)).forceUpdate(); + verify(mDeviceUpdater, never()).forceUpdate(); } @Test @@ -324,7 +349,7 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mPreferenceGroup.addPreference(mPreference1); mController.setPreferenceGroup(mPreferenceGroup); mController.onDeviceRemoved(mPreference1); - verify(mPreferenceGroup, times(0)).setVisible(false); + verify(mPreferenceGroup, never()).setVisible(false); assertThat(mPreferenceGroup.isVisible()).isTrue(); } @@ -344,7 +369,7 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mController.updateVisibility(); shadowOf(Looper.getMainLooper()).idle(); - verify(mPreferenceGroup, times(0)).setVisible(anyBoolean()); + verify(mPreferenceGroup, never()).setVisible(anyBoolean()); } @Test @@ -411,4 +436,64 @@ public class AudioSharingDeviceVolumeGroupControllerTest { verify(mPreference1).setOrder(0); verify(mPreference2).setOrder(1); } + + @Test + public void onDeviceVolumeChanged_updatePreference() { + when(mPreference1.getProgress()).thenReturn(TEST_MAX_VOLUME_VALUE); + mController.setPreferenceGroup(mPreferenceGroup); + mController.onDeviceAdded(mPreference1); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1); + + mController.mVolumeControlCallback.onDeviceVolumeChanged(mDevice1, TEST_VOLUME_VALUE); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mPreference1).setProgress(TEST_VOLUME_VALUE); + } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_updateGroup() { + when(mState.getBisSyncState()).thenReturn(new ArrayList<>()); + // onReceiveStateChanged with unconnected state will do nothing + mController.mBroadcastAssistantCallback.onReceiveStateChanged( + mDevice1, /* sourceId= */ 1, mState); + verify(mDeviceUpdater, never()).forceUpdate(); + + // onReceiveStateChanged with connected state will update group preference + List bisSyncState = new ArrayList<>(); + bisSyncState.add(1L); + when(mState.getBisSyncState()).thenReturn(bisSyncState); + mController.mBroadcastAssistantCallback.onReceiveStateChanged( + mDevice1, /* sourceId= */ 1, mState); + verify(mDeviceUpdater).forceUpdate(); + + // onSourceRemoved will update group preference + mController.mBroadcastAssistantCallback.onSourceRemoved( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + verify(mDeviceUpdater, times(2)).forceUpdate(); + } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() { + mController.mBroadcastAssistantCallback.onSearchStarted(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStartFailed(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStopped(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSearchStopFailed(/* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceAdded( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceAddFailed( + mDevice1, mSource, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceRemoveFailed( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceModified( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceModifyFailed( + mDevice1, /* sourceId= */ 1, /* reason= */ 1); + mController.mBroadcastAssistantCallback.onSourceFound(mSource); + mController.mBroadcastAssistantCallback.onSourceLost(/* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + + // Above callbacks won't update group preference + verify(mDeviceUpdater, never()).forceUpdate(); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java index 633bc06aa30..00e210dec89 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDialogHandlerTest.java @@ -19,7 +19,11 @@ package com.android.settings.connecteddevice.audiosharing; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -27,6 +31,8 @@ import static org.robolectric.Shadows.shadowOf; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcast; +import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; @@ -38,7 +44,6 @@ import android.util.Pair; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import androidx.test.core.app.ApplicationProvider; import com.android.settings.bluetooth.Utils; import com.android.settings.testutils.FakeFeatureFactory; @@ -71,6 +76,7 @@ import org.robolectric.shadows.androidx.fragment.FragmentController; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; @RunWith(RobolectricTestRunner.class) @Config( @@ -82,6 +88,7 @@ public class AudioSharingDialogHandlerTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private static final int TEST_SOURCE_ID = 1; private static final String TEST_DEVICE_NAME1 = "test1"; private static final String TEST_DEVICE_NAME2 = "test2"; private static final String TEST_DEVICE_NAME3 = "test3"; @@ -109,15 +116,22 @@ public class AudioSharingDialogHandlerTest { @Mock private BluetoothDevice mDevice3; @Mock private BluetoothDevice mDevice4; @Mock private LeAudioProfile mLeAudioProfile; - private Fragment mParentFragment; @Mock private BluetoothLeBroadcastReceiveState mState; + @Mock private BluetoothLeBroadcastMetadata mMetadata; + private Fragment mParentFragment; private Context mContext; private AudioSharingDialogHandler mHandler; private FakeFeatureFactory mFeatureFactory; @Before public void setup() { - mContext = ApplicationProvider.getApplicationContext(); + mParentFragment = new Fragment(); + FragmentController.setupFragment( + mParentFragment, + FragmentActivity.class, + 0 /* containerViewId */, + null /* bundle */); + mContext = mParentFragment.getContext(); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager; mLocalBtManager = Utils.getLocalBtManager(mContext); ShadowBluetoothAdapter shadowBluetoothAdapter = @@ -135,6 +149,7 @@ public class AudioSharingDialogHandlerTest { List bisSyncState = new ArrayList<>(); bisSyncState.add(1L); when(mState.getBisSyncState()).thenReturn(bisSyncState); + when(mState.getSourceId()).thenReturn(TEST_SOURCE_ID); when(mLeAudioProfile.isEnabled(any())).thenReturn(true); when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1); when(mCachedDevice1.getDevice()).thenReturn(mDevice1); @@ -158,12 +173,6 @@ public class AudioSharingDialogHandlerTest { when(mCacheManager.findDevice(mDevice2)).thenReturn(mCachedDevice2); when(mCacheManager.findDevice(mDevice3)).thenReturn(mCachedDevice3); when(mCacheManager.findDevice(mDevice4)).thenReturn(mCachedDevice4); - mParentFragment = new Fragment(); - FragmentController.setupFragment( - mParentFragment, - FragmentActivity.class, - 0 /* containerViewId */, - null /* bundle */); mHandler = new AudioSharingDialogHandler(mContext, mParentFragment); } @@ -269,6 +278,10 @@ public class AudioSharingDialogHandlerTest { AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT .ordinal(), 2)); + AudioSharingJoinDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onShareClick(); + verify(mBroadcast).startPrivateBroadcast(); } @Test @@ -309,6 +322,10 @@ public class AudioSharingDialogHandlerTest { AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT .ordinal(), 1)); + AudioSharingJoinDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onShareClick(); + verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); } @Test @@ -351,6 +368,11 @@ public class AudioSharingDialogHandlerTest { AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT .ordinal(), 1)); + AudioSharingDisconnectDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onItemClick(AudioSharingUtils.buildAudioSharingDeviceItem(mCachedDevice3)); + verify(mAssistant).removeSource(mDevice3, TEST_SOURCE_ID); + verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); } @Test @@ -363,7 +385,7 @@ public class AudioSharingDialogHandlerTest { when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of()); mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ false); shadowOf(Looper.getMainLooper()).idle(); - verify(mCachedDevice2, times(0)).setActive(); + verify(mCachedDevice2, never()).setActive(); } @Test @@ -415,7 +437,7 @@ public class AudioSharingDialogHandlerTest { when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of()); mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false); shadowOf(Looper.getMainLooper()).idle(); - verify(mCachedDevice1, times(0)).setActive(); + verify(mCachedDevice1, never()).setActive(); } @Test @@ -455,6 +477,10 @@ public class AudioSharingDialogHandlerTest { AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT .ordinal(), 2)); + AudioSharingJoinDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onShareClick(); + verify(mBroadcast).startPrivateBroadcast(); } @Test @@ -495,6 +521,10 @@ public class AudioSharingDialogHandlerTest { AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT .ordinal(), 1)); + AudioSharingJoinDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onShareClick(); + verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); } @Test @@ -536,6 +566,11 @@ public class AudioSharingDialogHandlerTest { AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT .ordinal(), 1)); + AudioSharingDisconnectDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onItemClick(AudioSharingUtils.buildAudioSharingDeviceItem(mCachedDevice3)); + verify(mAssistant).removeSource(mDevice3, TEST_SOURCE_ID); + verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); } @Test @@ -588,7 +623,106 @@ public class AudioSharingDialogHandlerTest { SettingsEnums.DIALOG_STOP_AUDIO_SHARING); } + @Test + public void closeOpeningDialogsOtherThan() { + setUpBroadcast(true); + ImmutableList deviceList = ImmutableList.of(mDevice3); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(deviceList); + when(mAssistant.getAllSources(mDevice3)).thenReturn(ImmutableList.of(mState)); + mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ true); + shadowOf(Looper.getMainLooper()).idle(); + List childFragments = mParentFragment.getChildFragmentManager().getFragments(); + assertThat(childFragments) + .comparingElementsUsing(TAG_EQUALS) + .containsExactly(AudioSharingStopDialogFragment.tag()); + + deviceList = ImmutableList.of(mDevice1, mDevice3); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(deviceList); + when(mAssistant.getAllSources(mDevice1)).thenReturn(ImmutableList.of()); + mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false); + shadowOf(Looper.getMainLooper()).idle(); + childFragments = mParentFragment.getChildFragmentManager().getFragments(); + assertThat(childFragments) + .comparingElementsUsing(TAG_EQUALS) + .containsExactly(AudioSharingJoinDialogFragment.tag()); + + verify(mFeatureFactory.metricsFeatureProvider) + .action( + mContext, + SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS, + SettingsEnums.DIALOG_STOP_AUDIO_SHARING); + } + + @Test + public void registerCallbacks() { + Executor executor = mock(Executor.class); + mHandler.registerCallbacks(executor); + verify(mBroadcast) + .registerServiceCallBack(eq(executor), any(BluetoothLeBroadcast.Callback.class)); + } + + @Test + public void unregisterCallbacks() { + mHandler.unregisterCallbacks(); + verify(mBroadcast).unregisterServiceCallBack(any(BluetoothLeBroadcast.Callback.class)); + } + + @Test + public void onPlaybackStarted_addSource() { + setUpBroadcast(false); + ImmutableList deviceList = ImmutableList.of(mDevice1, mDevice3); + when(mAssistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED})) + .thenReturn(deviceList); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of()); + mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true); + shadowOf(Looper.getMainLooper()).idle(); + List childFragments = mParentFragment.getChildFragmentManager().getFragments(); + assertThat(childFragments) + .comparingElementsUsing(TAG_EQUALS) + .containsExactly(AudioSharingJoinDialogFragment.tag()); + AudioSharingJoinDialogFragment fragment = + (AudioSharingJoinDialogFragment) Iterables.getOnlyElement(childFragments); + AudioSharingJoinDialogFragment.DialogEventListener listener = fragment.getListener(); + assertThat(listener).isNotNull(); + listener.onShareClick(); + + setUpBroadcast(true); + mHandler.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false); + verify(mAssistant).addSource(mDevice3, mMetadata, /* isGroupOp= */ false); + } + + @Test + public void testBluetoothLeBroadcastCallbacks_doNothing() { + mHandler.mBroadcastCallback.onBroadcastStarted(/* reason= */ 1, /* broadcastId= */ 1); + mHandler.mBroadcastCallback.onBroadcastStopped(/* reason= */ 1, /* broadcastId= */ 1); + mHandler.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, mMetadata); + mHandler.mBroadcastCallback.onBroadcastUpdated(/* reason= */ 1, /* broadcastId= */ 1); + mHandler.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1); + mHandler.mBroadcastCallback.onPlaybackStopped(/* reason= */ 1, /* broadcastId= */ 1); + mHandler.mBroadcastCallback.onBroadcastStartFailed(/* reason= */ 1); + mHandler.mBroadcastCallback.onBroadcastStopFailed(/* reason= */ 1); + mHandler.mBroadcastCallback.onBroadcastUpdateFailed(/* reason= */ 1, /* broadcastId= */ 1); + + verify(mAssistant, never()) + .addSource( + any(BluetoothDevice.class), + any(BluetoothLeBroadcastMetadata.class), + anyBoolean()); + verify(mAssistant, never()).removeSource(any(BluetoothDevice.class), anyInt()); + } + private void setUpBroadcast(boolean isBroadcasting) { when(mBroadcast.isEnabled(any())).thenReturn(isBroadcasting); + if (isBroadcasting) { + when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata); + } } } 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 8f85feb89fd..012f88c29fc 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java @@ -22,11 +22,13 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -36,6 +38,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.content.BroadcastReceiver; @@ -181,7 +184,7 @@ public class AudioSharingSwitchBarControllerTest { doNothing() .when(mAssistant) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); - mSwitchBar = new SettingsMainSwitchBar(mContext); + mSwitchBar = spy(new SettingsMainSwitchBar(mContext)); mSwitchBar.setDisabledByAdmin(mock(RestrictedLockUtils.EnforcedAdmin.class)); mOnAudioSharingStateChanged = false; mOnAudioSharingServiceConnected = false; @@ -258,15 +261,15 @@ public class AudioSharingSwitchBarControllerTest { public void onStart_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStart(mLifecycleOwner); - verify(mContext, times(0)) + verify(mContext, never()) .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class), anyInt()); - verify(mBroadcast, times(0)) + verify(mBroadcast, never()) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcast.Callback.class)); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mBtProfileManager, times(0)).addServiceListener(mController); + verify(mBtProfileManager, never()).addServiceListener(mController); } @Test @@ -279,10 +282,10 @@ public class AudioSharingSwitchBarControllerTest { verify(mContext) .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class), anyInt()); - verify(mBroadcast, times(0)) + verify(mBroadcast, never()) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcast.Callback.class)); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); verify(mBtProfileManager).addServiceListener(mController); @@ -305,7 +308,7 @@ public class AudioSharingSwitchBarControllerTest { verify(mAssistant) .registerServiceCallBack( any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mBtProfileManager, times(0)).addServiceListener(mController); + verify(mBtProfileManager, never()).addServiceListener(mController); assertThat(mSwitchBar.isChecked()).isTrue(); assertThat(mSwitchBar.isEnabled()).isTrue(); } @@ -314,12 +317,12 @@ public class AudioSharingSwitchBarControllerTest { public void onStop_flagOff_doNothing() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mController.onStop(mLifecycleOwner); - verify(mContext, times(0)).unregisterReceiver(any(BroadcastReceiver.class)); - verify(mBroadcast, times(0)) + verify(mContext, never()).unregisterReceiver(any(BroadcastReceiver.class)); + verify(mBroadcast, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcast.Callback.class)); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); - verify(mBtProfileManager, times(0)).removeServiceListener(mController); + verify(mBtProfileManager, never()).removeServiceListener(mController); } @Test @@ -331,9 +334,9 @@ public class AudioSharingSwitchBarControllerTest { verify(mContext).unregisterReceiver(any(BroadcastReceiver.class)); verify(mBtProfileManager).removeServiceListener(mController); - verify(mBroadcast, times(0)) + verify(mBroadcast, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcast.Callback.class)); - verify(mAssistant, times(0)) + verify(mAssistant, never()) .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); } @@ -358,7 +361,7 @@ public class AudioSharingSwitchBarControllerTest { when(mBtnView.isEnabled()).thenReturn(true); when(mBroadcast.isEnabled(null)).thenReturn(true); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); - verify(mBroadcast, times(0)).startPrivateBroadcast(); + verify(mBroadcast, never()).startPrivateBroadcast(); } @Test @@ -372,7 +375,7 @@ public class AudioSharingSwitchBarControllerTest { doNothing().when(mBroadcast).startPrivateBroadcast(); mController.onCheckedChanged(mBtnView, /* isChecked= */ true); assertThat(mSwitchBar.isChecked()).isFalse(); - verify(mBroadcast, times(0)).startPrivateBroadcast(); + verify(mBroadcast, never()).startPrivateBroadcast(); } @Test @@ -407,7 +410,7 @@ public class AudioSharingSwitchBarControllerTest { when(mBroadcast.isEnabled(null)).thenReturn(false); when(mBroadcast.getLatestBroadcastId()).thenReturn(1); mController.onCheckedChanged(mBtnView, /* isChecked= */ false); - verify(mBroadcast, times(0)).stopBroadcast(anyInt()); + verify(mBroadcast, never()).stopBroadcast(anyInt()); } @Test @@ -465,4 +468,46 @@ public class AudioSharingSwitchBarControllerTest { .ordinal(), 1)); } + + @Test + public void testBluetoothLeBroadcastCallbacks_updateSwitch() { + mOnAudioSharingStateChanged = false; + mSwitchBar.setChecked(false); + when(mBroadcast.isEnabled(any())).thenReturn(false); + mController.mBroadcastCallback.onBroadcastStartFailed(/* reason= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mSwitchBar.isChecked()).isFalse(); + assertThat(mOnAudioSharingStateChanged).isFalse(); + + when(mBroadcast.isEnabled(any())).thenReturn(true); + mController.mBroadcastCallback.onBroadcastStarted(/* reason= */ 1, /* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mSwitchBar.isChecked()).isTrue(); + assertThat(mOnAudioSharingStateChanged).isTrue(); + + mOnAudioSharingStateChanged = false; + mController.mBroadcastCallback.onBroadcastStopFailed(/* reason= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mSwitchBar.isChecked()).isTrue(); + assertThat(mOnAudioSharingStateChanged).isFalse(); + + when(mBroadcast.isEnabled(any())).thenReturn(false); + mController.mBroadcastCallback.onBroadcastStopped(/* reason= */ 1, /* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + assertThat(mSwitchBar.isChecked()).isFalse(); + assertThat(mOnAudioSharingStateChanged).isTrue(); + } + + @Test + public void testBluetoothLeBroadcastCallbacks_doNothing() { + BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); + mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, metadata); + mController.mBroadcastCallback.onBroadcastUpdated(/* reason= */ 1, /* broadcastId= */ 1); + mController.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1); + mController.mBroadcastCallback.onPlaybackStopped(/* reason= */ 1, /* broadcastId= */ 1); + mController.mBroadcastCallback.onBroadcastUpdateFailed( + /* reason= */ 1, /* broadcastId= */ 1); + verify(mSwitchBar, never()).setChecked(anyBoolean()); + assertThat(mOnAudioSharingStateChanged).isFalse(); + } }