diff --git a/res/values/config.xml b/res/values/config.xml
index ec611f09694..e3ec74f2636 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -128,4 +128,7 @@
doesn't interact well with scroll view -->
true
+
+
+
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index e0e8e4e0df9..3f7bd2582c1 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -342,6 +342,21 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
return super.onPreferenceTreeClick(preference);
}
+ public static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
+ boolean serviceEnabled) {
+ final String serviceState = serviceEnabled
+ ? context.getString(R.string.accessibility_summary_state_enabled)
+ : context.getString(R.string.accessibility_summary_state_disabled);
+ final CharSequence serviceSummary = info.loadSummary(context.getPackageManager());
+ final String stateSummaryCombo = context.getString(
+ R.string.preference_summary_default_combination,
+ serviceState, serviceSummary);
+
+ return (TextUtils.isEmpty(serviceSummary))
+ ? serviceState
+ : stateSummaryCombo;
+ }
+
private void handleToggleTextContrastPreferenceClick() {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
@@ -543,15 +558,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
preference.setSummary(R.string.accessibility_summary_state_stopped);
description = getString(R.string.accessibility_description_state_stopped);
} else {
- final String serviceState = serviceEnabled ?
- getString(R.string.accessibility_summary_state_enabled) :
- getString(R.string.accessibility_summary_state_disabled);
- final CharSequence serviceSummary = info.loadSummary(getPackageManager());
- final String stateSummaryCombo = getString(
- R.string.preference_summary_default_combination,
- serviceState, serviceSummary);
- preference.setSummary((TextUtils.isEmpty(serviceSummary)) ? serviceState
- : stateSummaryCombo);
+ final CharSequence serviceSummary = getServiceSummary(getContext(), info,
+ serviceEnabled);
+ preference.setSummary(serviceSummary);
}
// Disable all accessibility services that are not permitted.
diff --git a/src/com/android/settings/accessibility/AccessibilitySlicePreferenceController.java b/src/com/android/settings/accessibility/AccessibilitySlicePreferenceController.java
new file mode 100644
index 00000000000..6b9a480ff81
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilitySlicePreferenceController.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 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 android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * PreferenceController for accessibility services to be used by Slices.
+ * Wraps the common logic which enables accessibility services and checks their availability.
+ *
+ * Should not be used in a {@link com.android.settings.dashboard.DashboardFragment}.
+ */
+public class AccessibilitySlicePreferenceController extends TogglePreferenceController {
+
+ private final ComponentName mComponentName;
+
+ private final int ON = 1;
+ private final int OFF = 0;
+
+ public AccessibilitySlicePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mComponentName = ComponentName.unflattenFromString(getPreferenceKey());
+
+ if (mComponentName == null) {
+ throw new IllegalArgumentException(
+ "Illegal Component Name from: " + preferenceKey);
+ }
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo();
+ return serviceInfo == null
+ ? "" : AccessibilitySettings.getServiceSummary(mContext, serviceInfo, isChecked());
+ }
+
+ @Override
+ public boolean isChecked() {
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ final boolean accessibilityEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_ENABLED, OFF) == ON;
+
+ if (!accessibilityEnabled) {
+ return false;
+ }
+
+ final Set componentNames =
+ AccessibilityUtils.getEnabledServicesFromSettings(mContext);
+
+ return componentNames.contains(mComponentName);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ if (getAccessibilityServiceInfo() == null) {
+ return false;
+ }
+ AccessibilityUtils.setAccessibilityServiceState(mContext, mComponentName, isChecked);
+ return isChecked == isChecked(); // Verify that it was probably changed.
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // Return unsupported when the service is disabled or not installed.
+ return getAccessibilityServiceInfo() == null ? DISABLED_UNSUPPORTED : AVAILABLE;
+ }
+
+ private AccessibilityServiceInfo getAccessibilityServiceInfo() {
+ final AccessibilityManager accessibilityManager = mContext.getSystemService(
+ AccessibilityManager.class);
+ final List serviceList =
+ accessibilityManager.getInstalledAccessibilityServiceList();
+
+ for (AccessibilityServiceInfo serviceInfo : serviceList) {
+ if (mComponentName.equals(serviceInfo.getComponentName())) {
+ return serviceInfo;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 1a73ea760e5..d8f990a194d 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -148,7 +148,7 @@ public class SettingsSliceProvider extends SliceProvider {
void loadSlice(Uri uri) {
long startBuildTime = System.currentTimeMillis();
- SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
+ final SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
mSliceDataCache.put(uri, sliceData);
getContext().getContentResolver().notifyChange(uri, null /* content observer */);
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index a2479a2da05..8b5dd71f056 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -113,13 +113,13 @@ public class SliceBuilderUtils {
* - key
*
* Examples of valid paths are:
- * - intent/wifi
- * - intent/bluetooth
- * - action/wifi
- * - action/accessibility/servicename
+ * - /intent/wifi
+ * - /intent/bluetooth
+ * - /action/wifi
+ * - /action/accessibility/servicename
*
* @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
- * @return Pair whose first element {@code true} if the path is prepended with "action", and
+ * @return Pair whose first element {@code true} if the path is prepended with "intent", and
* second is a key.
*/
public static Pair getPathData(Uri uri) {
@@ -133,10 +133,10 @@ public class SliceBuilderUtils {
throw new IllegalArgumentException("Uri (" + uri + ") has incomplete path: " + path);
}
- final boolean isInline = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_ACTION,
+ final boolean isIntent = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_INTENT,
split[1]);
- return new Pair<>(isInline, split[2]);
+ return new Pair<>(isIntent, split[2]);
}
/**
@@ -215,8 +215,8 @@ public class SliceBuilderUtils {
static Intent getContentIntent(Context context, SliceData sliceData) {
final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
- sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
- 0 /* TODO */);
+ sliceData.getFragmentClassName(), sliceData.getKey(),
+ sliceData.getScreenTitle().toString(), 0 /* TODO */);
intent.setClassName(context.getPackageName(), SubSettings.class.getName());
intent.setData(contentUri);
return intent;
diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java
index c02b1135699..2caf6e6be17 100644
--- a/src/com/android/settings/slices/SliceData.java
+++ b/src/com/android/settings/slices/SliceData.java
@@ -57,7 +57,7 @@ public class SliceData {
private final String mSummary;
- private final String mScreenTitle;
+ private final CharSequence mScreenTitle;
private final int mIconResource;
@@ -84,7 +84,7 @@ public class SliceData {
return mSummary;
}
- public String getScreenTitle() {
+ public CharSequence getScreenTitle() {
return mScreenTitle;
}
@@ -146,7 +146,7 @@ public class SliceData {
private String mSummary;
- private String mScreenTitle;
+ private CharSequence mScreenTitle;
private int mIconResource;
@@ -175,7 +175,7 @@ public class SliceData {
return this;
}
- public Builder setScreenTitle(String screenTitle) {
+ public Builder setScreenTitle(CharSequence screenTitle) {
mScreenTitle = screenTitle;
return this;
}
diff --git a/src/com/android/settings/slices/SliceDataConverter.java b/src/com/android/settings/slices/SliceDataConverter.java
index 7cf1994f9ed..27724bfddf5 100644
--- a/src/com/android/settings/slices/SliceDataConverter.java
+++ b/src/com/android/settings/slices/SliceDataConverter.java
@@ -23,7 +23,12 @@ import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_PLATFO
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
@@ -32,9 +37,14 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
+import android.view.accessibility.AccessibilityManager;
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
@@ -46,10 +56,16 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
- * Converts {@link DashboardFragment} to {@link SliceData}.
+ * Converts all Slice sources into {@link SliceData}.
+ * This includes:
+ * - All {@link DashboardFragment DashboardFragments} indexed by settings search
+ * - Accessibility services
*/
class SliceDataConverter {
@@ -101,6 +117,8 @@ class SliceDataConverter {
mSliceData.addAll(providerSliceData);
}
+ final List a11ySliceData = getAccessibilitySliceData();
+ mSliceData.addAll(a11ySliceData);
return mSliceData;
}
@@ -208,4 +226,58 @@ class SliceDataConverter {
}
return xmlSliceData;
}
+
+ private List getAccessibilitySliceData() {
+ final List sliceData = new ArrayList<>();
+
+ final String accessibilityControllerClassName =
+ AccessibilitySlicePreferenceController.class.getName();
+ final String fragmentClassName = AccessibilitySettings.class.getName();
+ final CharSequence screenTitle = mContext.getText(R.string.accessibility_settings);
+
+ final SliceData.Builder sliceDataBuilder = new SliceData.Builder()
+ .setFragmentName(fragmentClassName)
+ .setScreenTitle(screenTitle)
+ .setPreferenceControllerClassName(accessibilityControllerClassName);
+
+ final Set a11yServiceNames = new HashSet<>();
+ Collections.addAll(a11yServiceNames, mContext.getResources()
+ .getStringArray(R.array.config_settings_slices_accessibility_components));
+ final List installedServices = getAccessibilityServiceInfoList();
+ final PackageManager packageManager = mContext.getPackageManager();
+
+ for (AccessibilityServiceInfo a11yServiceInfo : installedServices) {
+ final ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ final String packageName = serviceInfo.packageName;
+ final ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
+ final String flattenedName = componentName.flattenToString();
+
+ if (!a11yServiceNames.contains(flattenedName)) {
+ continue;
+ }
+
+ final String title = resolveInfo.loadLabel(packageManager).toString();
+ int iconResource = resolveInfo.getIconResource();
+ if (iconResource == 0) {
+ iconResource = R.mipmap.ic_accessibility_generic;
+ }
+
+ sliceDataBuilder.setKey(flattenedName)
+ .setTitle(title)
+ .setIcon(iconResource)
+ .setSliceType(SliceData.SliceType.SWITCH);
+
+ sliceData.add(sliceDataBuilder.build());
+ }
+
+ return sliceData;
+ }
+
+ @VisibleForTesting
+ List getAccessibilityServiceInfoList() {
+ final AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(
+ mContext);
+ return accessibilityManager.getInstalledAccessibilityServiceList();
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
index 82b3506f739..7823d217cc8 100644
--- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java
+++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
@@ -76,7 +76,7 @@ public class SlicesDatabaseAccessor {
*/
public SliceData getSliceDataFromKey(String key) {
Cursor cursor = getIndexedSliceData(key);
- return buildSliceData(cursor, null /* uri */, false /* isInlineOnly */);
+ return buildSliceData(cursor, null /* uri */, false /* isIntentOnly */);
}
private Cursor getIndexedSliceData(String path) {
@@ -111,7 +111,7 @@ public class SlicesDatabaseAccessor {
.toString();
}
- private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isInlineOnly) {
+ private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isIntentOnly) {
final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
@@ -127,7 +127,7 @@ public class SlicesDatabaseAccessor {
int sliceType = cursor.getInt(
cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
- if (!isInlineOnly) {
+ if (isIntentOnly) {
sliceType = SliceData.SliceType.INTENT;
}
diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java
index d7de7bc27a9..e2ab40d407d 100644
--- a/src/com/android/settings/slices/SlicesIndexer.java
+++ b/src/com/android/settings/slices/SlicesIndexer.java
@@ -104,7 +104,7 @@ class SlicesIndexer implements Runnable {
values.put(IndexColumns.KEY, dataRow.getKey());
values.put(IndexColumns.TITLE, dataRow.getTitle());
values.put(IndexColumns.SUMMARY, dataRow.getSummary());
- values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle());
+ values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle().toString());
values.put(IndexColumns.ICON_RESOURCE, dataRow.getIconResource());
values.put(IndexColumns.FRAGMENT, dataRow.getFragmentClassName());
values.put(IndexColumns.CONTROLLER, dataRow.getPreferenceController());
diff --git a/tests/robotests/assets/grandfather_slice_controller_not_in_xml b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
index 5a0999739df..d2274e65faf 100644
--- a/tests/robotests/assets/grandfather_slice_controller_not_in_xml
+++ b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
@@ -1,2 +1,4 @@
com.android.settings.testutils.FakeToggleController
-com.android.settings.testutils.FakeSliderController
\ No newline at end of file
+com.android.settings.testutils.FakeSliderController
+com.android.settings.core.TogglePreferenceControllerTest$FakeToggle
+com.android.settings.accessibility.AccessibilitySlicePreferenceController
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 39620d8e0a5..cecc9c59c59 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -62,4 +62,9 @@
false
false
true
+
+
+
+ - fake_package/fake_service
+
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java
new file mode 100644
index 00000000000..fe6d1a3f5fd
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 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.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_UNSUPPORTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowAccessibilityManager;
+import org.xmlpull.v1.XmlPullParserException;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AccessibilitySlicePreferenceControllerTest {
+
+ private final String PACKAGE_NAME = "com.android.settings.fake";
+ private final String CLASS_NAME = "com.android.settings.fake.classname";
+ private final String SERVICE_NAME = PACKAGE_NAME + "/" + CLASS_NAME;
+
+ private Context mContext;
+
+ private AccessibilitySlicePreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ Settings.Secure.putInt(contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED, 1 /* on */);
+ Settings.Secure.putString(contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ SERVICE_NAME);
+
+ // Register the fake a11y Service
+ ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
+ RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
+ shadowAccessibilityManager.setInstalledAccessibilityServiceList(getFakeServiceList());
+
+ mController = new AccessibilitySlicePreferenceController(mContext, SERVICE_NAME);
+ }
+
+ @Test
+ public void getAvailability_availableService_returnsAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailability_unknownService_returnsUnsupported() {
+ AccessibilitySlicePreferenceController controller =
+ new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
+
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
+ }
+
+ @Test
+ public void setChecked_availableService_serviceIsEnabled() {
+ mController.setChecked(true);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void setNotChecked_availableService_serviceIsDisabled() {
+ mController.setChecked(false);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_serviceEnabled_returnsTrue() {
+ AccessibilityUtils.setAccessibilityServiceState(mContext,
+ ComponentName.unflattenFromString(mController.getPreferenceKey()), true);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void isChecked_serviceNotEnabled_returnsFalse() {
+ AccessibilitySlicePreferenceController controller =
+ new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
+
+ assertThat(controller.isChecked()).isFalse();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void illegalServiceName_exceptionThrown() {
+ new AccessibilitySlicePreferenceController(mContext, "not_split_by_slash");
+ }
+
+ private List getFakeServiceList() {
+ final List infoList = new ArrayList<>();
+
+ final ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = PACKAGE_NAME;
+ serviceInfo.name = CLASS_NAME;
+
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+
+ try {
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
+ mContext);
+ ComponentName componentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+ info.setComponentName(componentName);
+ infoList.add(info);
+ } catch (XmlPullParserException | IOException e) {
+
+ }
+
+ return infoList;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 59eb7ceceaf..32cbd42cf54 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -277,7 +277,7 @@ public class SliceBuilderUtilsTest {
final Pair pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isFalse();
+ assertThat(pathPair.first).isTrue();
assertThat(pathPair.second).isEqualTo(KEY);
}
@@ -291,7 +291,7 @@ public class SliceBuilderUtilsTest {
final Pair pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isTrue();
+ assertThat(pathPair.first).isFalse();
assertThat(pathPair.second).isEqualTo(KEY);
}
@@ -316,7 +316,7 @@ public class SliceBuilderUtilsTest {
final Pair pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isTrue();
+ assertThat(pathPair.first).isFalse();
assertThat(pathPair.second).isEqualTo(KEY + "/" + KEY);
}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
index 36c27548c13..adc7a96e7e1 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
@@ -17,8 +17,22 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
import com.android.settings.search.FakeIndexProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
@@ -32,17 +46,29 @@ import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceDataConverterTest {
- private final String fakeKey = "key";
- private final String fakeTitle = "title";
- private final String fakeSummary = "summary";
- private final String fakeScreenTitle = "screen_title";
- private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
- private final String fakeControllerName = FakePreferenceController.class.getName();
+ private final String FAKE_KEY = "key";
+ private final String FAKE_TITLE = "title";
+ private final String FAKE_SUMMARY = "summary";
+ private final String FAKE_SCREEN_TITLE = "screen_title";
+ private final String FAKE_FRAGMENT_CLASSNAME = FakeIndexProvider.class.getName();
+ private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
+
+ private final String ACCESSIBILITY_FRAGMENT = AccessibilitySettings.class.getName();
+ private final String A11Y_CONTROLLER_NAME =
+ AccessibilitySlicePreferenceController.class.getName();
+ private final String FAKE_SERVICE_NAME = "fake_service";
+ private final String FAKE_ACCESSIBILITY_PACKAGE = "fake_package";
+ private final String FAKE_A11Y_SERVICE_NAME =
+ FAKE_ACCESSIBILITY_PACKAGE + "/" + FAKE_SERVICE_NAME;
+ private final int FAKE_ICON = 1234;
+
+ private Context mContext;
private SliceDataConverter mSliceDataConverter;
private SearchFeatureProvider mSearchFeatureProvider;
@@ -50,7 +76,8 @@ public class SliceDataConverterTest {
@Before
public void setUp() {
- mSliceDataConverter = new SliceDataConverter(RuntimeEnvironment.application);
+ mContext = RuntimeEnvironment.application;
+ mSliceDataConverter = spy(new SliceDataConverter(RuntimeEnvironment.application));
mSearchFeatureProvider = new SearchFeatureProviderImpl();
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.searchFeatureProvider = mSearchFeatureProvider;
@@ -68,20 +95,64 @@ public class SliceDataConverterTest {
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues()
.add(FakeIndexProvider.class);
+ doReturn(getFakeService()).when(mSliceDataConverter).getAccessibilityServiceInfoList();
+
List sliceDataList = mSliceDataConverter.getSliceData();
- assertThat(sliceDataList).hasSize(1);
- SliceData fakeSlice = sliceDataList.get(0);
+ assertThat(sliceDataList).hasSize(2);
+ SliceData fakeSlice0 = sliceDataList.get(0);
+ SliceData fakeSlice1 = sliceDataList.get(1);
- assertThat(fakeSlice.getKey()).isEqualTo(fakeKey);
- assertThat(fakeSlice.getTitle()).isEqualTo(fakeTitle);
- assertThat(fakeSlice.getSummary()).isEqualTo(fakeSummary);
- assertThat(fakeSlice.getScreenTitle()).isEqualTo(fakeScreenTitle);
+ // Should not assume the order of the data list.
+ if (TextUtils.equals(fakeSlice0.getKey(), FAKE_KEY)) {
+ assertFakeSlice(fakeSlice0);
+ assertFakeA11ySlice(fakeSlice1);
+ } else {
+ assertFakeSlice(fakeSlice1);
+ assertFakeA11ySlice(fakeSlice0);
+ }
+ }
+
+ private void assertFakeSlice(SliceData fakeSlice) {
+ assertThat(fakeSlice.getKey()).isEqualTo(FAKE_KEY);
+ assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(fakeSlice.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(fakeSlice.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
assertThat(fakeSlice.getIconResource()).isNotNull();
assertThat(fakeSlice.getUri()).isNull();
- assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
- assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName);
- assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); // from XML
+ assertThat(fakeSlice.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_CLASSNAME);
+ assertThat(fakeSlice.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
+ assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
}
+
+ private void assertFakeA11ySlice(SliceData fakeSlice) {
+ assertThat(fakeSlice.getKey()).isEqualTo(FAKE_A11Y_SERVICE_NAME);
+ assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(fakeSlice.getSummary()).isNull();
+ assertThat(fakeSlice.getScreenTitle()).isEqualTo(
+ mContext.getString(R.string.accessibility_settings));
+ assertThat(fakeSlice.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(fakeSlice.getUri()).isNull();
+ assertThat(fakeSlice.getFragmentClassName()).isEqualTo(ACCESSIBILITY_FRAGMENT);
+ assertThat(fakeSlice.getPreferenceController()).isEqualTo(A11Y_CONTROLLER_NAME);
+ }
+
+ // This is fragile. Should be replaced by a proper fake Service if possible.
+ private List getFakeService() {
+ List serviceInfoList = new ArrayList<>();
+ AccessibilityServiceInfo serviceInfo = spy(new AccessibilityServiceInfo());
+
+ ResolveInfo resolveInfo = spy(new ResolveInfo());
+ resolveInfo.serviceInfo = new ServiceInfo();
+ resolveInfo.serviceInfo.name = FAKE_SERVICE_NAME;
+ resolveInfo.serviceInfo.packageName = FAKE_ACCESSIBILITY_PACKAGE;
+ doReturn(FAKE_TITLE).when(resolveInfo).loadLabel(any(PackageManager.class));
+ doReturn(FAKE_ICON).when(resolveInfo).getIconResource();
+
+ doReturn(resolveInfo).when(serviceInfo).getResolveInfo();
+ serviceInfoList.add(serviceInfo);
+
+ return serviceInfoList;
+ }
}
\ No newline at end of file