Show turn off talkback dialog if needed in AudioStreamConfirmDialog.

Test: atest
Bug: b/362151254
Flag: com.android.settingslib.flags.enable_le_audio_sharing
Change-Id: I29a20394193eca46ad8f42ffa0bceaad6f08da86
This commit is contained in:
chelseahao
2025-02-13 11:54:48 +08:00
committed by Chelsea Hao
parent 87a4a3dec8
commit 1dfd19e5e0
6 changed files with 265 additions and 10 deletions

View File

@@ -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;

View File

@@ -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.
*
* <p>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.</p>
*
* @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<ComponentName> getEnabledScreenReaderServices(Context context) {
AccessibilityManager manager = context.getSystemService(AccessibilityManager.class);
if (manager == null) {
return Collections.emptySet();
}
Set<String> screenReaderServices = new HashSet<>();
Collections.addAll(screenReaderServices, context.getResources()
.getStringArray(R.array.config_preinstalled_screen_reader_services));
if (screenReaderServices.isEmpty()) {
return Collections.emptySet();
}
Set<ComponentName> enabledScreenReaderServices = new HashSet<>();
List<AccessibilityServiceInfo> 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<ComponentName> services) {
for (ComponentName service : services) {
Log.d(TAG, "setScreenReaderOff(): " + service);
setAccessibilityServiceState(context, service, false);
}
}
}