Merge changes from topics "a11y_qs_attr_integration", "a11y_qs_tooltip_1p"

* changes:
  Integrate new accessibility tileService attr into settings
  Support accessibility settings load title from quick settings panel
  Show quick setting tooltips after shortcut edit dialog dismiss
  Show quick setting tooltips after shortcut tutorial dialog dismiss
This commit is contained in:
Menghan Li
2022-02-09 07:07:08 +00:00
committed by Android (Google) Code Review
9 changed files with 513 additions and 30 deletions

View File

@@ -221,6 +221,13 @@ public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
extras.putString(AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME,
new ComponentName(packageName, settingsClassName).flattenToString());
}
final String tileServiceClassName = info.getTileServiceClassName();
if (!TextUtils.isEmpty(tileServiceClassName)) {
extras.putString(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME,
new ComponentName(packageName, tileServiceClassName).flattenToString());
}
extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, info.getAnimatedImageRes());

View File

@@ -46,6 +46,7 @@ import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
@@ -125,9 +126,15 @@ public final class AccessibilityGestureNavigationTutorial {
}
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes) {
return createAccessibilityTutorialDialog(context, shortcutTypes, mOnClickListener);
}
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes,
@Nullable DialogInterface.OnClickListener negativeButtonListener) {
return new AlertDialog.Builder(context)
.setView(createShortcutNavigationContentView(context, shortcutTypes))
.setNegativeButton(R.string.accessibility_tutorial_dialog_button, mOnClickListener)
.setNegativeButton(R.string.accessibility_tutorial_dialog_button,
negativeButtonListener)
.create();
}

View File

@@ -97,6 +97,7 @@ public class AccessibilitySettings extends DashboardFragment {
static final String EXTRA_SETTINGS_TITLE = "settings_title";
static final String EXTRA_COMPONENT_NAME = "component_name";
static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
static final String EXTRA_TILE_SERVICE_COMPONENT_NAME = "tile_service_component_name";
static final String EXTRA_VIDEO_RAW_RESOURCE_ID = "video_resource";
static final String EXTRA_LAUNCHED_FROM_SUW = "from_suw";
static final String EXTRA_ANIMATED_IMAGE_RES = "animated_image_res";
@@ -573,11 +574,13 @@ public class AccessibilitySettings extends DashboardFragment {
serviceEnabled);
final String htmlDescription = info.loadHtmlDescription(mPm);
final String settingsClassName = info.getSettingsActivityName();
final String tileServiceClassName = info.getTileServiceClassName();
putBasicExtras(preference, prefKey, title, description, imageRes, htmlDescription,
componentName);
putServiceExtras(preference, resolveInfo, serviceEnabled);
putSettingsExtras(preference, packageName, settingsClassName);
putTileServiceExtras(preference, packageName, tileServiceClassName);
preferenceList.add(preference);
}
@@ -631,10 +634,13 @@ public class AccessibilitySettings extends DashboardFragment {
final int imageRes = info.getAnimatedImageRes();
final String htmlDescription = info.loadHtmlDescription(mPm);
final String settingsClassName = info.getSettingsActivityName();
final String tileServiceClassName = info.getTileServiceClassName();
putBasicExtras(preference, prefKey, title, description, imageRes, htmlDescription,
componentName);
putSettingsExtras(preference, componentName.getPackageName(), settingsClassName);
putTileServiceExtras(preference, componentName.getPackageName(),
tileServiceClassName);
preferenceList.add(preference);
}
@@ -730,7 +736,11 @@ public class AccessibilitySettings extends DashboardFragment {
/**
* Puts the service extras into {@link RestrictedPreference}'s getExtras().
*
* Called by {@link AccessibilityServiceInfo} for now.
* <p><b>Note:</b> Called by {@link AccessibilityServiceInfo}.</p>
*
* @param preference The preference we are configuring.
* @param resolveInfo The service resolve info.
* @param serviceEnabled Whether the accessibility service is enabled.
*/
private void putServiceExtras(RestrictedPreference preference, ResolveInfo resolveInfo,
Boolean serviceEnabled) {
@@ -743,7 +753,12 @@ public class AccessibilitySettings extends DashboardFragment {
/**
* Puts the settings extras into {@link RestrictedPreference}'s getExtras().
*
* Called when settings UI is needed.
* <p><b>Note:</b> Called when settings UI is needed.</p>
*
* @param preference The preference we are configuring.
* @param packageName Package of accessibility feature.
* @param settingsClassName The component name of an activity that allows the user to modify
* the settings for this accessibility feature.
*/
private void putSettingsExtras(RestrictedPreference preference, String packageName,
String settingsClassName) {
@@ -756,5 +771,27 @@ public class AccessibilitySettings extends DashboardFragment {
new ComponentName(packageName, settingsClassName).flattenToString());
}
}
/**
* Puts the information about a particular application
* {@link android.service.quicksettings.TileService} into {@link RestrictedPreference}'s
* getExtras().
*
* <p><b>Note:</b> Called when a tooltip of
* {@link android.service.quicksettings.TileService} is needed.</p>
*
* @param preference The preference we are configuring.
* @param packageName Package of accessibility feature.
* @param tileServiceClassName The component name of tileService is associated with this
* accessibility feature.
*/
private void putTileServiceExtras(RestrictedPreference preference, String packageName,
String tileServiceClassName) {
final Bundle extras = preference.getExtras();
if (!TextUtils.isEmpty(tileServiceClassName)) {
extras.putString(EXTRA_TILE_SERVICE_COMPONENT_NAME,
new ComponentName(packageName, tileServiceClassName).flattenToString());
}
}
}
}

View File

@@ -20,9 +20,11 @@ import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logA
import android.accessibilityservice.AccessibilityShortcutInfo;
import android.app.ActivityOptions;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
@@ -51,6 +53,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
private static final String TAG = "LaunchA11yActivity";
private static final String EMPTY_STRING = "";
protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference";
private ComponentName mTileComponentName;
@Override
public int getMetricsCategory() {
@@ -106,6 +109,13 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
AccessibilitySettings.EXTRA_SETTINGS_TITLE);
mSettingsIntent = TextUtils.isEmpty(settingsTitle) ? null : getSettingsIntent(arguments);
mSettingsTitle = (mSettingsIntent == null) ? null : settingsTitle;
// Tile service.
if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) {
final String tileServiceComponentName = arguments.getString(
AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME);
mTileComponentName = ComponentName.unflattenFromString(tileServiceComponentName);
}
}
@Override
@@ -116,13 +126,31 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
@Override
ComponentName getTileComponentName() {
return null;
return mTileComponentName;
}
@Override
CharSequence getTileName() {
final ComponentName componentName = getTileComponentName();
if (componentName == null) {
return null;
}
return loadTileLabel(getPrefContext(), componentName);
}
@Override
public Dialog onCreateDialog(int dialogId) {
switch (dialogId) {
case AccessibilityDialogUtils.DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
final Dialog dialog = AccessibilityGestureNavigationTutorial
.createAccessibilityTutorialDialog(getPrefContext(),
getUserShortcutTypes(), this::callOnTutorialDialogButtonClicked);
dialog.setCanceledOnTouchOutside(false);
return dialog;
default:
return super.onCreateDialog(dialogId);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
@@ -208,4 +236,22 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
return settingsIntent;
}
/**
* This method will be invoked when a button in the tutorial dialog is clicked.
*
* @param dialog The dialog that received the click
* @param which The button that was clicked
*/
private void callOnTutorialDialogButtonClicked(DialogInterface dialog, int which) {
dialog.dismiss();
showQuickSettingsTooltipIfNeeded();
}
@Override
protected void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) {
super.callOnAlertDialogCheckboxClicked(dialog, which);
showQuickSettingsTooltipIfNeeded(getShortcutTypeCheckBoxValue());
}
}

View File

@@ -65,6 +65,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
private static final String EMPTY_STRING = "";
private Dialog mWarningDialog;
private ComponentName mTileComponentName;
private BroadcastReceiver mPackageRemovedReceiver;
private boolean mDisabledStateLogged = false;
private long mStartTimeMillsForLogging = 0;
@@ -168,9 +169,9 @@ public class ToggleAccessibilityServicePreferenceFragment extends
@Override
public Dialog onCreateDialog(int dialogId) {
switch (dialogId) {
case DialogEnums.ENABLE_WARNING_FROM_TOGGLE: {
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
switch (dialogId) {
case DialogEnums.ENABLE_WARNING_FROM_TOGGLE:
if (info == null) {
return null;
}
@@ -178,10 +179,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends
.createCapabilitiesDialog(getPrefContext(), info,
this::onDialogButtonFromEnableToggleClicked,
this::onDialogButtonFromUninstallClicked);
break;
}
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE: {
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
return mWarningDialog;
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE:
if (info == null) {
return null;
}
@@ -189,10 +188,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends
.createCapabilitiesDialog(getPrefContext(), info,
this::onDialogButtonFromShortcutToggleClicked,
this::onDialogButtonFromUninstallClicked);
break;
}
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT: {
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
return mWarningDialog;
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT:
if (info == null) {
return null;
}
@@ -200,23 +197,24 @@ public class ToggleAccessibilityServicePreferenceFragment extends
.createCapabilitiesDialog(getPrefContext(), info,
this::onDialogButtonFromShortcutClicked,
this::onDialogButtonFromUninstallClicked);
break;
}
case DialogEnums.DISABLE_WARNING_FROM_TOGGLE: {
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
return mWarningDialog;
case DialogEnums.DISABLE_WARNING_FROM_TOGGLE:
if (info == null) {
return null;
}
mWarningDialog = AccessibilityServiceWarning
.createDisableDialog(getPrefContext(), info,
this::onDialogButtonFromDisableToggleClicked);
break;
}
default: {
mWarningDialog = super.onCreateDialog(dialogId);
}
}
return mWarningDialog;
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
final Dialog dialog = AccessibilityGestureNavigationTutorial
.createAccessibilityTutorialDialog(getPrefContext(),
getUserShortcutTypes(), this::callOnTutorialDialogButtonClicked);
dialog.setCanceledOnTouchOutside(false);
return dialog;
default:
return super.onCreateDialog(dialogId);
}
}
@Override
@@ -243,13 +241,17 @@ public class ToggleAccessibilityServicePreferenceFragment extends
@Override
ComponentName getTileComponentName() {
return null;
return mTileComponentName;
}
@Override
CharSequence getTileName() {
final ComponentName componentName = getTileComponentName();
if (componentName == null) {
return null;
}
return loadTileLabel(getPrefContext(), componentName);
}
@Override
protected void updateSwitchBarToggleSwitch() {
@@ -386,6 +388,12 @@ public class ToggleAccessibilityServicePreferenceFragment extends
mPackageName = getAccessibilityServiceInfo().getResolveInfo().loadLabel(
getPackageManager());
if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) {
final String tileServiceComponentName = arguments.getString(
AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME);
mTileComponentName = ComponentName.unflattenFromString(tileServiceComponentName);
}
mStartTimeMillsForLogging = arguments.getLong(AccessibilitySettings.EXTRA_TIME_FOR_LOGGING);
}
@@ -488,6 +496,23 @@ public class ToggleAccessibilityServicePreferenceFragment extends
mWarningDialog.dismiss();
}
/**
* This method will be invoked when a button in the tutorial dialog is clicked.
*
* @param dialog The dialog that received the click
* @param which The button that was clicked
*/
private void callOnTutorialDialogButtonClicked(DialogInterface dialog, int which) {
dialog.dismiss();
showQuickSettingsTooltipIfNeeded();
}
@Override
protected void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) {
super.callOnAlertDialogCheckboxClicked(dialog, which);
showQuickSettingsTooltipIfNeeded(getShortcutTypeCheckBoxValue());
}
void onDialogButtonFromShortcutClicked(View view) {
final int viewId = view.getId();
if (viewId == R.id.permission_enable_allow_button) {

View File

@@ -25,7 +25,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.icu.text.CaseMap;
import android.net.Uri;
@@ -33,6 +35,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.quicksettings.TileService;
import android.text.Html;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -798,6 +801,19 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
}
/**
* Shows the quick settings tooltip if the quick settings service and the shortcut are assigned.
* The tooltip only shows once.
*
* @param shortcutType The shortcut type.
*/
protected void showQuickSettingsTooltipIfNeeded(@UserShortcutType int shortcutType) {
if (shortcutType == AccessibilityUtil.UserShortcutType.EMPTY) {
return;
}
showQuickSettingsTooltipIfNeeded();
}
/**
* Shows the quick settings tooltip if the quick settings service is assigned. The tooltip only
* shows once.
@@ -830,4 +846,20 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
tileComponentName);
mNeedsQSTooltipReshow = false;
}
/** Returns user visible name of the tile by given {@link ComponentName}. */
protected CharSequence loadTileLabel(Context context, ComponentName componentName) {
final PackageManager packageManager = context.getPackageManager();
final Intent queryIntent = new Intent(TileService.ACTION_QS_TILE);
final List<ResolveInfo> resolveInfos =
packageManager.queryIntentServices(queryIntent, PackageManager.GET_META_DATA);
for (ResolveInfo info : resolveInfos) {
final ServiceInfo serviceInfo = info.serviceInfo;
if (TextUtils.equals(componentName.getPackageName(), serviceInfo.packageName)
&& TextUtils.equals(componentName.getClassName(), serviceInfo.name)) {
return serviceInfo.loadLabel(packageManager);
}
}
return null;
}
}

View File

@@ -22,26 +22,41 @@ import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutT
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.DialogInterface;
import androidx.appcompat.app.AlertDialog;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/** Tests for {@link AccessibilityGestureNavigationTutorial}. */
@RunWith(RobolectricTestRunner.class)
public final class AccessibilityGestureNavigationTutorialTest {
private Context mContext;
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private DialogInterface.OnClickListener mMockOnClickListener;
private final Context mContext = ApplicationProvider.getApplicationContext();
private int mShortcutTypes;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mContext.setTheme(R.style.Theme_AppCompat);
mShortcutTypes = /* initial */ 0;
}
@@ -86,4 +101,28 @@ public final class AccessibilityGestureNavigationTutorialTest {
mShortcutTypes)).hasSize(/* expectedSize= */ 2);
assertThat(alertDialog).isNotNull();
}
@Test
public void performClickOnNegativeButton_turnOnSoftwareShortcut_dismiss() {
mShortcutTypes |= UserShortcutType.SOFTWARE;
final AlertDialog alertDialog =
createAccessibilityTutorialDialog(mContext, mShortcutTypes);
alertDialog.show();
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
assertThat(alertDialog.isShowing()).isFalse();
}
@Test
public void performClickOnNegativeButton_turnOnSoftwareShortcut_callOnClickListener() {
mShortcutTypes |= UserShortcutType.SOFTWARE;
final AlertDialog alertDialog =
createAccessibilityTutorialDialog(mContext, mShortcutTypes, mMockOnClickListener);
alertDialog.show();
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
verify(mMockOnClickListener).onClick(alertDialog, DialogInterface.BUTTON_NEGATIVE);
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.service.quicksettings.TileService;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowPackageManager;
import java.util.Arrays;
/** Tests for {@link LaunchAccessibilityActivityPreferenceFragment} */
@RunWith(RobolectricTestRunner.class)
public class LaunchAccessibilityActivityPreferenceFragmentTest {
private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
private static final String PLACEHOLDER_TILE_CLASS_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final String PLACEHOLDER_TILE_CLASS_NAME2 =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder2";
private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
private static final String PLACEHOLDER_TILE_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final String PLACEHOLDER_TILE_NAME2 =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder2";
private TestLaunchAccessibilityActivityPreferenceFragment mFragment;
private PreferenceScreen mScreen;
private Context mContext = ApplicationProvider.getApplicationContext();
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceManager mPreferenceManager;
@Before
public void setUpTestFragment() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new TestLaunchAccessibilityActivityPreferenceFragment());
when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
when(mFragment.getContext()).thenReturn(mContext);
mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
doReturn(mScreen).when(mFragment).getPreferenceScreen();
}
@Test
public void getTileName_noTileServiceAssigned_noMatchString() {
final CharSequence tileName = mFragment.getTileName();
assertThat(tileName.toString()).isEqualTo("");
}
@Test
public void getTileName_hasOneTileService_haveMatchString() {
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
final ResolveInfo info = new ResolveInfo();
info.serviceInfo = new FakeServiceInfo();
info.serviceInfo.packageName = PLACEHOLDER_PACKAGE_NAME;
info.serviceInfo.name = PLACEHOLDER_TILE_CLASS_NAME;
final ShadowPackageManager shadowPackageManager =
Shadows.shadowOf(mContext.getPackageManager());
shadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info));
final CharSequence tileName = mFragment.getTileName();
assertThat(tileName.toString()).isEqualTo(PLACEHOLDER_TILE_NAME);
}
@Test
public void getTileName_hasTwoTileServices_haveMatchString() {
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
final ResolveInfo info = new ResolveInfo();
info.serviceInfo = new FakeServiceInfo();
info.serviceInfo.packageName = PLACEHOLDER_PACKAGE_NAME;
info.serviceInfo.name = PLACEHOLDER_TILE_CLASS_NAME;
final ResolveInfo info2 = new ResolveInfo();
info2.serviceInfo = new FakeServiceInfo2();
info2.serviceInfo.packageName = PLACEHOLDER_PACKAGE_NAME;
info2.serviceInfo.name = PLACEHOLDER_TILE_CLASS_NAME2;
final ShadowPackageManager shadowPackageManager =
Shadows.shadowOf(mContext.getPackageManager());
shadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info, info2));
final CharSequence tileName = mFragment.getTileName();
assertThat(tileName.toString()).isEqualTo(PLACEHOLDER_TILE_NAME);
}
private static class FakeServiceInfo extends ServiceInfo {
public String loadLabel(PackageManager mgr) {
return PLACEHOLDER_TILE_NAME;
}
}
private static class FakeServiceInfo2 extends ServiceInfo {
public String loadLabel(PackageManager mgr) {
return PLACEHOLDER_TILE_NAME2;
}
}
private static class TestLaunchAccessibilityActivityPreferenceFragment
extends LaunchAccessibilityActivityPreferenceFragment {
@Override
protected ComponentName getTileComponentName() {
return PLACEHOLDER_TILE_COMPONENT_NAME;
}
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.service.quicksettings.TileService;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowPackageManager;
import java.util.Arrays;
/** Tests for {@link ToggleAccessibilityServicePreferenceFragment} */
@RunWith(RobolectricTestRunner.class)
public class ToggleAccessibilityServicePreferenceFragmentTest {
private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
private static final String PLACEHOLDER_TILE_CLASS_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final String PLACEHOLDER_TILE_CLASS_NAME2 =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder2";
private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
private static final String PLACEHOLDER_TILE_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final String PLACEHOLDER_TILE_NAME2 =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder2";
private TestToggleAccessibilityServicePreferenceFragment mFragment;
private PreferenceScreen mScreen;
private Context mContext = ApplicationProvider.getApplicationContext();
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceManager mPreferenceManager;
@Before
public void setUpTestFragment() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new TestToggleAccessibilityServicePreferenceFragment());
when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
when(mFragment.getContext()).thenReturn(mContext);
mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
doReturn(mScreen).when(mFragment).getPreferenceScreen();
}
@Test
public void getTileName_noTileServiceAssigned_noMatchString() {
final CharSequence tileName = mFragment.getTileName();
assertThat(tileName.toString()).isEqualTo("");
}
@Test
public void getTileName_hasOneTileService_haveMatchString() {
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
final ResolveInfo info = new ResolveInfo();
info.serviceInfo = new FakeServiceInfo();
info.serviceInfo.packageName = PLACEHOLDER_PACKAGE_NAME;
info.serviceInfo.name = PLACEHOLDER_TILE_CLASS_NAME;
final ShadowPackageManager shadowPackageManager =
Shadows.shadowOf(mContext.getPackageManager());
shadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info));
final CharSequence tileName = mFragment.getTileName();
assertThat(tileName.toString()).isEqualTo(PLACEHOLDER_TILE_NAME);
}
@Test
public void getTileName_hasTwoTileServices_haveMatchString() {
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
final ResolveInfo info = new ResolveInfo();
info.serviceInfo = new FakeServiceInfo();
info.serviceInfo.packageName = PLACEHOLDER_PACKAGE_NAME;
info.serviceInfo.name = PLACEHOLDER_TILE_CLASS_NAME;
final ResolveInfo info2 = new ResolveInfo();
info2.serviceInfo = new FakeServiceInfo2();
info2.serviceInfo.packageName = PLACEHOLDER_PACKAGE_NAME;
info2.serviceInfo.name = PLACEHOLDER_TILE_CLASS_NAME2;
final ShadowPackageManager shadowPackageManager =
Shadows.shadowOf(mContext.getPackageManager());
shadowPackageManager.setResolveInfosForIntent(tileProbe, Arrays.asList(info, info2));
final CharSequence tileName = mFragment.getTileName();
assertThat(tileName.toString()).isEqualTo(PLACEHOLDER_TILE_NAME);
}
private static class FakeServiceInfo extends ServiceInfo {
public String loadLabel(PackageManager mgr) {
return PLACEHOLDER_TILE_NAME;
}
}
private static class FakeServiceInfo2 extends ServiceInfo {
public String loadLabel(PackageManager mgr) {
return PLACEHOLDER_TILE_NAME2;
}
}
private static class TestToggleAccessibilityServicePreferenceFragment
extends ToggleAccessibilityServicePreferenceFragment {
@Override
protected ComponentName getTileComponentName() {
return PLACEHOLDER_TILE_COMPONENT_NAME;
}
}
}