Loading res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -14427,6 +14427,10 @@ Data usage charges may apply.</string> <string name="audio_streams_add_source_failed_state_summary">Can\u0027t connect. Try again.</string> <!-- The preference summary when connecting [CHAR LIMIT=NONE] --> <string name="audio_streams_connecting_summary">Connecting\u2026</string> <!-- Le audio streams audio failed dialog title [CHAR LIMIT=NONE] --> <string name="audio_streams_dialog_failed_to_join">Failed to join audio stream</string> <!-- Le audio streams audio failed dialog detail [CHAR LIMIT=NONE] --> <string name="audio_streams_dialog_failed_to_join_detail"><xliff:g example="LE headset" id="device_name">%1$s</xliff:g> could not connect to audio stream</string> <!-- Le audio streams audio lost dialog title [CHAR LIMIT=NONE] --> <string name="audio_streams_dialog_stream_is_not_available">Audio stream isn\u0027t available</string> <!-- Le audio streams audio lost dialog subtitle [CHAR LIMIT=NONE] --> src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java +18 −4 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; Loading @@ -25,8 +27,11 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.bluetooth.Utils; import com.android.settingslib.utils.ThreadUtils; import java.util.List; class AddSourceWaitForResponseState extends AudioStreamStateHandler { @VisibleForTesting static final int AUDIO_STREAM_ADD_SOURCE_WAIT_FOR_RESPONSE_STATE_SUMMARY = Loading Loading @@ -78,13 +83,21 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { preference.getContext(), SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_TIMEOUT, preference.getSourceOriginForLogging().ordinal()); List<BluetoothDevice> devices = AudioStreamsHelper.getConnectedBluetoothDevices( Utils.getLocalBluetoothManager( preference.getContext()), /* inSharingOnly= */ false); String deviceName = devices.isEmpty() ? "" : TextUtils.emptyIfNull( devices.getFirst().getAlias()); ThreadUtils.postOnMainThread( () -> { if (controller.getFragment() != null) { showBroadcastUnavailableNoRetryDialog( controller.getFragment(), preference.getContext(), AudioStreamsHelper.getBroadcastName(metadata)); AudioStreamsHelper.getBroadcastName(metadata), deviceName); } }); } Loading @@ -105,14 +118,15 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { } private void showBroadcastUnavailableNoRetryDialog( Fragment fragment, Context context, String broadcastName) { Fragment fragment, Context context, String broadcastName, String deviceName) { var broadcastUnavailableNoRetryDialog = new AudioStreamsDialogFragment.DialogBuilder(context) .setTitle( context.getString( R.string.audio_streams_dialog_stream_is_not_available)) R.string.audio_streams_dialog_failed_to_join)) .setSubTitle1(broadcastName) .setSubTitle2(context.getString(R.string.audio_streams_is_not_playing)) .setSubTitle2(context.getString( R.string.audio_streams_dialog_failed_to_join_detail, deviceName)) .setRightButtonText(context.getString(R.string.audio_streams_dialog_close)) .setRightButtonOnClickListener(AlertDialog::dismiss); Loading tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseStateTest.java +25 −2 Original line number Diff line number Diff line Loading @@ -30,14 +30,20 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.LocalBluetoothManager; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; Loading @@ -56,10 +62,13 @@ import java.util.concurrent.TimeUnit; @Config( shadows = { ShadowAlertDialog.class, ShadowAudioStreamsHelper.class, ShadowBluetoothUtils.class, }) public class AddSourceWaitForResponseStateTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private static final int BROADCAST_ID = 1; private static final String ALIAS = "device name"; private final Context mContext = spy(ApplicationProvider.getApplicationContext()); @Mock private AudioStreamPreference mMockPreference; @Mock private AudioStreamsProgressCategoryController mMockController; Loading @@ -67,11 +76,17 @@ public class AddSourceWaitForResponseStateTest { @Mock private AudioStreamScanHelper mScanHelper; @Mock private BluetoothLeBroadcastMetadata mMockMetadata; @Mock private AudioStreamsRepository mMockRepository; @Mock private LocalBluetoothManager mLocalBluetoothManager; @Mock private BluetoothDevice mBluetoothDevice; private FakeFeatureFactory mFeatureFactory; private AddSourceWaitForResponseState mInstance; @Before public void setUp() { ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); mFeatureFactory = FakeFeatureFactory.setupForTest(); mInstance = new AddSourceWaitForResponseState(); when(mMockPreference.getContext()).thenReturn(mContext); Loading @@ -79,6 +94,12 @@ public class AddSourceWaitForResponseStateTest { .thenReturn(SourceOriginForLogging.QR_CODE_SCAN_SETTINGS); } @After public void tearDown() { ShadowAudioStreamsHelper.reset(); ShadowBluetoothUtils.reset(); } @Test public void testGetInstance() { mInstance = AddSourceWaitForResponseState.getInstance(); Loading Loading @@ -135,6 +156,8 @@ public class AddSourceWaitForResponseStateTest { @Test public void testPerformAction_timeout_addSource_sourceFailedToConnect() { ShadowAudioStreamsHelper.setConnectedBluetoothDevice(mBluetoothDevice); when(mBluetoothDevice.getAlias()).thenReturn(ALIAS); when(mMockPreference.getAudioStreamMetadata()).thenReturn(mMockMetadata); when(mMockPreference.isShown()).thenReturn(true); when(mMockPreference.getAudioStreamState()).thenReturn(mInstance.getStateEnum()); Loading @@ -160,8 +183,8 @@ public class AddSourceWaitForResponseStateTest { eq(mContext), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_TIMEOUT), eq(SourceOriginForLogging.QR_CODE_SCAN_SETTINGS.ordinal())); verify(mContext).getString(R.string.audio_streams_dialog_stream_is_not_available); verify(mContext).getString(R.string.audio_streams_is_not_playing); verify(mContext).getString(R.string.audio_streams_dialog_failed_to_join); verify(mContext).getString(R.string.audio_streams_dialog_failed_to_join_detail, ALIAS); verify(mContext).getString(R.string.audio_streams_dialog_close); } } tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java +13 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import java.util.Set; public class ShadowAudioStreamsHelper { private static AudioStreamsHelper sMockHelper; @Nullable private static CachedBluetoothDevice sCachedBluetoothDevice; @Nullable private static BluetoothDevice sBluetoothDevice; @Nullable private static ComponentName sEnabledScreenReaderService; public static void setUseMock(AudioStreamsHelper mockAudioStreamsHelper) { Loading @@ -57,6 +58,7 @@ public class ShadowAudioStreamsHelper { sMockHelper = null; sCachedBluetoothDevice = null; sEnabledScreenReaderService = null; sBluetoothDevice = null; } public static void setCachedBluetoothDeviceInSharingOrLeConnected( Loading @@ -64,6 +66,10 @@ public class ShadowAudioStreamsHelper { sCachedBluetoothDevice = cachedBluetoothDevice; } public static void setConnectedBluetoothDevice(BluetoothDevice bluetoothDevice) { sBluetoothDevice = bluetoothDevice; } public static void setEnabledScreenReaderService(ComponentName componentName) { sEnabledScreenReaderService = componentName; } Loading @@ -86,6 +92,13 @@ public class ShadowAudioStreamsHelper { return Optional.ofNullable(sCachedBluetoothDevice); } /** Gets {@link BluetoothDevice} that is le connected */ @Implementation public static List<BluetoothDevice> getConnectedBluetoothDevices( LocalBluetoothManager manager, boolean inSharingOnly) { return sBluetoothDevice == null ? Collections.emptyList() : List.of(sBluetoothDevice); } /** Retrieves a set of enabled screen reader services that are pre-installed. */ @Implementation public static Set<ComponentName> getEnabledScreenReaderServices(Context context) { Loading Loading
res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -14427,6 +14427,10 @@ Data usage charges may apply.</string> <string name="audio_streams_add_source_failed_state_summary">Can\u0027t connect. Try again.</string> <!-- The preference summary when connecting [CHAR LIMIT=NONE] --> <string name="audio_streams_connecting_summary">Connecting\u2026</string> <!-- Le audio streams audio failed dialog title [CHAR LIMIT=NONE] --> <string name="audio_streams_dialog_failed_to_join">Failed to join audio stream</string> <!-- Le audio streams audio failed dialog detail [CHAR LIMIT=NONE] --> <string name="audio_streams_dialog_failed_to_join_detail"><xliff:g example="LE headset" id="device_name">%1$s</xliff:g> could not connect to audio stream</string> <!-- Le audio streams audio lost dialog title [CHAR LIMIT=NONE] --> <string name="audio_streams_dialog_stream_is_not_available">Audio stream isn\u0027t available</string> <!-- Le audio streams audio lost dialog subtitle [CHAR LIMIT=NONE] -->
src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java +18 −4 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; Loading @@ -25,8 +27,11 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.bluetooth.Utils; import com.android.settingslib.utils.ThreadUtils; import java.util.List; class AddSourceWaitForResponseState extends AudioStreamStateHandler { @VisibleForTesting static final int AUDIO_STREAM_ADD_SOURCE_WAIT_FOR_RESPONSE_STATE_SUMMARY = Loading Loading @@ -78,13 +83,21 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { preference.getContext(), SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_TIMEOUT, preference.getSourceOriginForLogging().ordinal()); List<BluetoothDevice> devices = AudioStreamsHelper.getConnectedBluetoothDevices( Utils.getLocalBluetoothManager( preference.getContext()), /* inSharingOnly= */ false); String deviceName = devices.isEmpty() ? "" : TextUtils.emptyIfNull( devices.getFirst().getAlias()); ThreadUtils.postOnMainThread( () -> { if (controller.getFragment() != null) { showBroadcastUnavailableNoRetryDialog( controller.getFragment(), preference.getContext(), AudioStreamsHelper.getBroadcastName(metadata)); AudioStreamsHelper.getBroadcastName(metadata), deviceName); } }); } Loading @@ -105,14 +118,15 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { } private void showBroadcastUnavailableNoRetryDialog( Fragment fragment, Context context, String broadcastName) { Fragment fragment, Context context, String broadcastName, String deviceName) { var broadcastUnavailableNoRetryDialog = new AudioStreamsDialogFragment.DialogBuilder(context) .setTitle( context.getString( R.string.audio_streams_dialog_stream_is_not_available)) R.string.audio_streams_dialog_failed_to_join)) .setSubTitle1(broadcastName) .setSubTitle2(context.getString(R.string.audio_streams_is_not_playing)) .setSubTitle2(context.getString( R.string.audio_streams_dialog_failed_to_join_detail, deviceName)) .setRightButtonText(context.getString(R.string.audio_streams_dialog_close)) .setRightButtonOnClickListener(AlertDialog::dismiss); Loading
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseStateTest.java +25 −2 Original line number Diff line number Diff line Loading @@ -30,14 +30,20 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.LocalBluetoothManager; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; Loading @@ -56,10 +62,13 @@ import java.util.concurrent.TimeUnit; @Config( shadows = { ShadowAlertDialog.class, ShadowAudioStreamsHelper.class, ShadowBluetoothUtils.class, }) public class AddSourceWaitForResponseStateTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private static final int BROADCAST_ID = 1; private static final String ALIAS = "device name"; private final Context mContext = spy(ApplicationProvider.getApplicationContext()); @Mock private AudioStreamPreference mMockPreference; @Mock private AudioStreamsProgressCategoryController mMockController; Loading @@ -67,11 +76,17 @@ public class AddSourceWaitForResponseStateTest { @Mock private AudioStreamScanHelper mScanHelper; @Mock private BluetoothLeBroadcastMetadata mMockMetadata; @Mock private AudioStreamsRepository mMockRepository; @Mock private LocalBluetoothManager mLocalBluetoothManager; @Mock private BluetoothDevice mBluetoothDevice; private FakeFeatureFactory mFeatureFactory; private AddSourceWaitForResponseState mInstance; @Before public void setUp() { ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; mLocalBluetoothManager = Utils.getLocalBtManager(mContext); mFeatureFactory = FakeFeatureFactory.setupForTest(); mInstance = new AddSourceWaitForResponseState(); when(mMockPreference.getContext()).thenReturn(mContext); Loading @@ -79,6 +94,12 @@ public class AddSourceWaitForResponseStateTest { .thenReturn(SourceOriginForLogging.QR_CODE_SCAN_SETTINGS); } @After public void tearDown() { ShadowAudioStreamsHelper.reset(); ShadowBluetoothUtils.reset(); } @Test public void testGetInstance() { mInstance = AddSourceWaitForResponseState.getInstance(); Loading Loading @@ -135,6 +156,8 @@ public class AddSourceWaitForResponseStateTest { @Test public void testPerformAction_timeout_addSource_sourceFailedToConnect() { ShadowAudioStreamsHelper.setConnectedBluetoothDevice(mBluetoothDevice); when(mBluetoothDevice.getAlias()).thenReturn(ALIAS); when(mMockPreference.getAudioStreamMetadata()).thenReturn(mMockMetadata); when(mMockPreference.isShown()).thenReturn(true); when(mMockPreference.getAudioStreamState()).thenReturn(mInstance.getStateEnum()); Loading @@ -160,8 +183,8 @@ public class AddSourceWaitForResponseStateTest { eq(mContext), eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_TIMEOUT), eq(SourceOriginForLogging.QR_CODE_SCAN_SETTINGS.ordinal())); verify(mContext).getString(R.string.audio_streams_dialog_stream_is_not_available); verify(mContext).getString(R.string.audio_streams_is_not_playing); verify(mContext).getString(R.string.audio_streams_dialog_failed_to_join); verify(mContext).getString(R.string.audio_streams_dialog_failed_to_join_detail, ALIAS); verify(mContext).getString(R.string.audio_streams_dialog_close); } }
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java +13 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import java.util.Set; public class ShadowAudioStreamsHelper { private static AudioStreamsHelper sMockHelper; @Nullable private static CachedBluetoothDevice sCachedBluetoothDevice; @Nullable private static BluetoothDevice sBluetoothDevice; @Nullable private static ComponentName sEnabledScreenReaderService; public static void setUseMock(AudioStreamsHelper mockAudioStreamsHelper) { Loading @@ -57,6 +58,7 @@ public class ShadowAudioStreamsHelper { sMockHelper = null; sCachedBluetoothDevice = null; sEnabledScreenReaderService = null; sBluetoothDevice = null; } public static void setCachedBluetoothDeviceInSharingOrLeConnected( Loading @@ -64,6 +66,10 @@ public class ShadowAudioStreamsHelper { sCachedBluetoothDevice = cachedBluetoothDevice; } public static void setConnectedBluetoothDevice(BluetoothDevice bluetoothDevice) { sBluetoothDevice = bluetoothDevice; } public static void setEnabledScreenReaderService(ComponentName componentName) { sEnabledScreenReaderService = componentName; } Loading @@ -86,6 +92,13 @@ public class ShadowAudioStreamsHelper { return Optional.ofNullable(sCachedBluetoothDevice); } /** Gets {@link BluetoothDevice} that is le connected */ @Implementation public static List<BluetoothDevice> getConnectedBluetoothDevices( LocalBluetoothManager manager, boolean inSharingOnly) { return sBluetoothDevice == null ? Collections.emptyList() : List.of(sBluetoothDevice); } /** Retrieves a set of enabled screen reader services that are pre-installed. */ @Implementation public static Set<ComponentName> getEnabledScreenReaderServices(Context context) { Loading