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

@@ -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<BluetoothDevice> 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<BluetoothDevice> devices = new ArrayList<>();

View File

@@ -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<ComponentName> 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<ComponentName> 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<ComponentName> 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<ComponentName>();
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);

View File

@@ -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<Integer, LocalBluetoothLeBroadcastSourceState> 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<ComponentName> getEnabledScreenReaderServices(Context context) {
if (sEnabledScreenReaderService != null) {
return Set.of(sEnabledScreenReaderService);
}
return Collections.emptySet();
}
@Implementation
public LocalBluetoothLeBroadcastAssistant getLeBroadcastAssistant() {
return sMockHelper.getLeBroadcastAssistant();