diff --git a/res/values/strings.xml b/res/values/strings.xml
index eb316e0a8eb..ae587496150 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -14081,6 +14081,12 @@
Stop listening
Connect compatible headphones
+
+ Turn off Talkback temporarily
+
+ Talkback cannot be used when listening to audio streams. Turn off talkback to start listening.
+
+ Turn off
Connect a device
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java
index d2e288f0d0b..1a9ef619581 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java
@@ -17,6 +17,8 @@
package com.android.settings.connecteddevice.audiosharing.audiostreams;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsDashboardFragment.KEY_BROADCAST_METADATA;
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsHelper.getEnabledScreenReaderServices;
+import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsHelper.setAccessibilityServiceOff;
import static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.SCHEME_BT_BROADCAST_METADATA;
import android.app.Activity;
@@ -41,6 +43,7 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.utils.ThreadUtils;
public class AudioStreamConfirmDialog extends InstrumentedDialogFragment {
private static final String TAG = "AudioStreamConfirmDialog";
@@ -86,6 +89,8 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment {
case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_FEATURE_UNSUPPORTED ->
getUnsupportedDialog();
case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_NO_LE_DEVICE -> getNoLeDeviceDialog();
+ case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_TURN_OFF_TALKBACK ->
+ getTurnOffTalkbackDialog();
case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_LISTEN -> getConfirmDialog();
default -> getErrorDialog();
};
@@ -168,6 +173,36 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment {
.build();
}
+ private Dialog getTurnOffTalkbackDialog() {
+ return new AudioStreamsDialogFragment.DialogBuilder(getActivity())
+ .setTitle(getString(R.string.audio_streams_dialog_turn_off_talkback_title))
+ .setSubTitle2(getString(R.string.audio_streams_dialog_turn_off_talkback_subtitle))
+ .setLeftButtonText(getString(R.string.cancel))
+ .setLeftButtonOnClickListener(
+ unused -> {
+ dismiss();
+ if (mActivity != null) {
+ mActivity.finish();
+ }
+ })
+ .setRightButtonText(
+ getString(R.string.audio_streams_dialog_turn_off_talkback_button))
+ .setRightButtonOnClickListener(
+ dialog -> {
+ var unused = ThreadUtils.postOnBackgroundThread(() -> {
+ var enabledScreenReader = getEnabledScreenReaderServices(mContext);
+ if (!enabledScreenReader.isEmpty()) {
+ setAccessibilityServiceOff(mContext, enabledScreenReader);
+ }
+ });
+ dismiss();
+ if (mActivity != null) {
+ mActivity.finish();
+ }
+ })
+ .build();
+ }
+
private Dialog getNoLeDeviceDialog() {
return new AudioStreamsDialogFragment.DialogBuilder(getActivity())
.setTitle(getString(R.string.audio_streams_dialog_no_le_device_title))
@@ -234,6 +269,9 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment {
if (!hasConnectedDevice) {
return SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_NO_LE_DEVICE;
}
+ if (!getEnabledScreenReaderServices(mContext).isEmpty()) {
+ return SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_TURN_OFF_TALKBACK;
+ }
return hasMetadata
? SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_LISTEN
: SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_DATA_ERROR;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java
index 0890870442f..12962bf2d6f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelper.java
@@ -19,6 +19,7 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_ID;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_TITLE;
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES;
+import static com.android.settingslib.accessibility.AccessibilityUtils.setAccessibilityServiceState;
import static com.android.settingslib.bluetooth.BluetoothUtils.isAudioSharingHysteresisModeFixAvailable;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.DECRYPTION_FAILED;
@@ -30,15 +31,18 @@ import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toMap;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudioContentMetadata;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.util.Log;
import android.util.Pair;
+import android.view.accessibility.AccessibilityManager;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentActivity;
@@ -56,9 +60,12 @@ import com.google.android.material.appbar.AppBarLayout;
import com.google.common.base.Strings;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -399,4 +406,55 @@ public class AudioStreamsHelper {
}
}
}
+
+ /**
+ * Retrieves a set of enabled screen reader services that are pre-installed.
+ *
+ *
This method checks the accessibility manager for enabled accessibility services
+ * and filters them based on a list of pre-installed screen reader service component names
+ * defined in the {@code config_preinstalled_screen_reader_services} resource array.
+ *
+ * @param context The context.
+ * @return A set of {@link ComponentName} objects representing the enabled pre-installed
+ * screen reader services, or an empty set if no services are found, or if an error occurs.
+ */
+ public static Set getEnabledScreenReaderServices(Context context) {
+ AccessibilityManager manager = context.getSystemService(AccessibilityManager.class);
+ if (manager == null) {
+ return Collections.emptySet();
+ }
+ Set screenReaderServices = new HashSet<>();
+ Collections.addAll(screenReaderServices, context.getResources()
+ .getStringArray(R.array.config_preinstalled_screen_reader_services));
+ if (screenReaderServices.isEmpty()) {
+ return Collections.emptySet();
+ }
+ Set enabledScreenReaderServices = new HashSet<>();
+ List enabledServices = manager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ for (AccessibilityServiceInfo service : enabledServices) {
+ ComponentName componentName = service.getComponentName();
+ if (screenReaderServices.contains(componentName.flattenToString())) {
+ enabledScreenReaderServices.add(componentName);
+ }
+ }
+ Log.d(TAG, "getEnabledScreenReaderServices(): " + enabledScreenReaderServices);
+ return enabledScreenReaderServices;
+ }
+
+ /**
+ * Turns off the specified accessibility services.
+ *
+ * This method iterates through a set of ComponentName objects, each representing an
+ * accessibility service, and disables them.
+ *
+ * @param context The application context.
+ * @param services A set of ComponentName objects representing the services to disable.
+ */
+ public static void setAccessibilityServiceOff(Context context, Set services) {
+ for (ComponentName service : services) {
+ Log.d(TAG, "setScreenReaderOff(): " + service);
+ setAccessibilityServiceState(context, service, false);
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
index d22130a7bbe..ac548059853 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialogTest.java
@@ -34,6 +34,7 @@ import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothStatusCodes;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -46,6 +47,7 @@ import androidx.fragment.app.FragmentActivity;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
@@ -74,12 +76,15 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
- ShadowBluetoothAdapter.class,
- ShadowBluetoothUtils.class,
+ ShadowBluetoothAdapter.class,
+ ShadowBluetoothUtils.class,
+ ShadowAudioStreamsHelper.class,
})
public class AudioStreamConfirmDialogTest {
- @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String VALID_METADATA =
"BLUETOOTH:UUID:184F;BN:VGVzdA==;AT:1;AD:00A1A1A1A1A1;BI:1E240;BC:VGVzdENvZGU=;"
+ "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;";
@@ -88,12 +93,18 @@ public class AudioStreamConfirmDialogTest {
+ "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;";
private static final String DEVICE_NAME = "device_name";
private final Context mContext = ApplicationProvider.getApplicationContext();
- @Mock private LocalBluetoothManager mLocalBluetoothManager;
- @Mock private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
- @Mock private LocalBluetoothLeBroadcast mBroadcast;
- @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
- @Mock private VolumeControlProfile mVolumeControl;
- @Mock private BluetoothDevice mBluetoothDevice;
+ @Mock
+ private LocalBluetoothManager mLocalBluetoothManager;
+ @Mock
+ private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+ @Mock
+ private LocalBluetoothLeBroadcast mBroadcast;
+ @Mock
+ private LocalBluetoothLeBroadcastAssistant mAssistant;
+ @Mock
+ private VolumeControlProfile mVolumeControl;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
private AudioStreamConfirmDialog mDialogFragment;
@Before
@@ -376,6 +387,66 @@ public class AudioStreamConfirmDialogTest {
verify(mDialogFragment.mActivity, times(2)).finish();
}
+ @Test
+ public void showDialog_turnOffTalkback() {
+ List devices = new ArrayList<>();
+ devices.add(mBluetoothDevice);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(devices);
+ when(mBluetoothDevice.getAlias()).thenReturn("");
+ ShadowAudioStreamsHelper.setEnabledScreenReaderService(new ComponentName("pkg", "class"));
+
+ Intent intent = new Intent();
+ intent.putExtra(KEY_BROADCAST_METADATA, VALID_METADATA);
+ FragmentController.of(mDialogFragment, intent)
+ .create(/* containerViewId= */ 0, /* bundle= */ null)
+ .start()
+ .resume()
+ .visible()
+ .get();
+ shadowMainLooper().idle();
+
+ assertThat(mDialogFragment.getMetricsCategory())
+ .isEqualTo(SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_TURN_OFF_TALKBACK);
+ assertThat(mDialogFragment.mActivity).isNotNull();
+ mDialogFragment.mActivity = spy(mDialogFragment.mActivity);
+
+ var dialog = mDialogFragment.getDialog();
+ assertThat(dialog).isNotNull();
+ assertThat(dialog.isShowing()).isTrue();
+
+ TextView title = dialog.findViewById(R.id.dialog_title);
+ assertThat(title).isNotNull();
+ assertThat(title.getText())
+ .isEqualTo(
+ mContext.getString(R.string.audio_streams_dialog_turn_off_talkback_title));
+ TextView subtitle1 = dialog.findViewById(R.id.dialog_subtitle);
+ assertThat(subtitle1).isNotNull();
+ assertThat(subtitle1.getVisibility()).isEqualTo(View.GONE);
+ TextView subtitle2 = dialog.findViewById(R.id.dialog_subtitle_2);
+ assertThat(subtitle2).isNotNull();
+ assertThat(subtitle2.getText())
+ .isEqualTo(mContext.getString(
+ R.string.audio_streams_dialog_turn_off_talkback_subtitle));
+ View leftButton = dialog.findViewById(R.id.left_button);
+ assertThat(leftButton).isNotNull();
+ assertThat(leftButton.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(leftButton.hasOnClickListeners()).isTrue();
+
+ leftButton.callOnClick();
+ assertThat(dialog.isShowing()).isFalse();
+
+ Button rightButton = dialog.findViewById(R.id.right_button);
+ assertThat(rightButton).isNotNull();
+ assertThat(rightButton.getText())
+ .isEqualTo(
+ mContext.getString(R.string.audio_streams_dialog_turn_off_talkback_button));
+ assertThat(rightButton.hasOnClickListeners()).isTrue();
+
+ rightButton.callOnClick();
+ assertThat(dialog.isShowing()).isFalse();
+ verify(mDialogFragment.mActivity, times(2)).finish();
+ }
+
@Test
public void showDialog_getDataStringFromIntent_confirmListen() {
List devices = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java
index ba37c83055a..36276036c6e 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsHelperTest.java
@@ -36,22 +36,28 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothStatusCodes;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.FragmentActivity;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowAccessibilityManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
+import com.android.settingslib.accessibility.AccessibilityUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
@@ -75,11 +81,14 @@ import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
+ ShadowAccessibilityManager.class,
ShadowThreadUtils.class,
ShadowBluetoothAdapter.class,
})
@@ -100,11 +109,17 @@ public class AudioStreamsHelperTest {
@Mock private CachedBluetoothDevice mCachedDevice;
@Mock private BluetoothDevice mDevice;
@Mock private BluetoothDevice mSourceDevice;
+ @Mock
+ private AccessibilityServiceInfo mTalkbackServiceInfo;
+ private ShadowAccessibilityManager mShadowAccessibilityManager;
private AudioStreamsHelper mHelper;
@Before
public void setUp() {
mSetFlagsRule.disableFlags(FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+ mShadowAccessibilityManager = Shadow.extract(
+ mContext.getSystemService(AccessibilityManager.class));
+ mShadowAccessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>());
ShadowBluetoothAdapter shadowBluetoothAdapter = Shadow.extract(
BluetoothAdapter.getDefaultAdapter());
shadowBluetoothAdapter.setEnabled(true);
@@ -348,6 +363,54 @@ public class AudioStreamsHelperTest {
verify(appBarLayout).setExpanded(eq(true));
}
+ @Test
+ public void getEnabledScreenReaderServices_noAccessibilityManager_returnEmpty() {
+ mShadowAccessibilityManager = null;
+ Set result = AudioStreamsHelper.getEnabledScreenReaderServices(mContext);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void getEnabledScreenReaderServices_notEnabled_returnEmpty() {
+ Resources resources = spy(mContext.getResources());
+ when(mContext.getResources()).thenReturn(resources);
+ when(resources.getStringArray(R.array.config_preinstalled_screen_reader_services))
+ .thenReturn(new String[]{"pkg/serviceClassName"});
+ mShadowAccessibilityManager.setEnabledAccessibilityServiceList(
+ new ArrayList<>());
+ Set result = AudioStreamsHelper.getEnabledScreenReaderServices(mContext);
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void getEnabledScreenReaderServices_enabled_returnService() {
+ Resources resources = spy(mContext.getResources());
+ when(mContext.getResources()).thenReturn(resources);
+ when(resources.getStringArray(R.array.config_preinstalled_screen_reader_services))
+ .thenReturn(new String[]{"pkg/serviceClassName"});
+ ComponentName expected = new ComponentName("pkg", "serviceClassName");
+ when(mTalkbackServiceInfo.getComponentName()).thenReturn(expected);
+ mShadowAccessibilityManager.setEnabledAccessibilityServiceList(
+ new ArrayList<>(List.of(mTalkbackServiceInfo)));
+ Set result = AudioStreamsHelper.getEnabledScreenReaderServices(mContext);
+
+ assertThat(result).isNotEmpty();
+ assertThat(result.iterator().next()).isEqualTo(expected);
+ }
+
+ @Test
+ public void setAccessibilityServiceOff_valueOff() {
+ ComponentName componentName = new ComponentName("pkg", "serviceClassName");
+ var target = new HashSet();
+ target.add(componentName);
+ AudioStreamsHelper.setAccessibilityServiceOff(mContext, target);
+
+ assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext,
+ UserHandle.myUserId())).isEmpty();
+ }
+
private void setUpFragment(
FragmentActivity fragmentActivity, AppBarLayout appBarLayout, int orientationPortrait) {
Resources resources = mock(Resources.class);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
index 1d3c7a0ddd6..1b79b96668b 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
@@ -21,6 +21,8 @@ import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssista
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.content.ComponentName;
+import android.content.Context;
import androidx.annotation.Nullable;
@@ -33,14 +35,17 @@ import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
@Implements(value = AudioStreamsHelper.class, callThroughByDefault = true)
public class ShadowAudioStreamsHelper {
private static AudioStreamsHelper sMockHelper;
@Nullable private static CachedBluetoothDevice sCachedBluetoothDevice;
+ @Nullable private static ComponentName sEnabledScreenReaderService;
public static void setUseMock(AudioStreamsHelper mockAudioStreamsHelper) {
sMockHelper = mockAudioStreamsHelper;
@@ -51,6 +56,7 @@ public class ShadowAudioStreamsHelper {
public static void reset() {
sMockHelper = null;
sCachedBluetoothDevice = null;
+ sEnabledScreenReaderService = null;
}
public static void setCachedBluetoothDeviceInSharingOrLeConnected(
@@ -58,6 +64,10 @@ public class ShadowAudioStreamsHelper {
sCachedBluetoothDevice = cachedBluetoothDevice;
}
+ public static void setEnabledScreenReaderService(ComponentName componentName) {
+ sEnabledScreenReaderService = componentName;
+ }
+
@Implementation
public Map getConnectedBroadcastIdAndState(
boolean hysteresisModeFixAvailable) {
@@ -76,6 +86,15 @@ public class ShadowAudioStreamsHelper {
return Optional.ofNullable(sCachedBluetoothDevice);
}
+ /** Retrieves a set of enabled screen reader services that are pre-installed. */
+ @Implementation
+ public static Set getEnabledScreenReaderServices(Context context) {
+ if (sEnabledScreenReaderService != null) {
+ return Set.of(sEnabledScreenReaderService);
+ }
+ return Collections.emptySet();
+ }
+
@Implementation
public LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
return sMockHelper.getLeBroadcastAssistant();