OSDN Git Service

Accessibility settings refresh.
authorSaige McVea <saigem@google.com>
Sat, 21 Jan 2017 04:23:09 +0000 (20:23 -0800)
committerSaige McVea <saigem@google.com>
Mon, 6 Mar 2017 23:08:42 +0000 (15:08 -0800)
Added logic for proper handling of new accessibility service categories. Preferences and
services are no longer distinctly separated - services are added after system preferences
in their appropriate category, or are grouped under "Downloaded services".

Bug: 30374533

Test: CTS tests updated to accommodate addition of summary.

Change-Id: I38255ede8880922e60487607f8d1bd520b1adf75

res/values/config.xml
res/values/strings.xml
res/xml/accessibility_settings.xml
src/com/android/settings/accessibility/AccessibilitySettings.java

index 0fa2b71..f81bf9b 100755 (executable)
     <!-- If the support features are enabled. -->
     <bool name="config_support_enabled">false</bool>
 
+    <!-- List containing the component names of pre-installed screen reader services. -->
+    <string-array name="config_preinstalled_screen_reader_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
+    <!-- List containing the component names of pre-installed audio and captioning services. -->
+    <string-array name="config_preinstalled_audio_and_caption_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
+    <!-- List containing the component names of pre-installed display services. -->
+    <string-array name="config_preinstalled_display_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
+    <!-- List containing the component names of pre-installed interaction control services. -->
+    <string-array name="config_preinstalled_interaction_control_services" translatable="false">
+        <!--
+        <item>com.example.package.first/com.example.class.FirstService</item>
+        <item>com.example.package.second/com.example.class.SecondService</item>
+        -->
+    </string-array>
+
 </resources>
index 1e1304e..6f2898d 100644 (file)
     <string name="vision_settings_title">Vision Settings</string>
     <!-- Settings description for a brief version of Vision-Related Accessibility Settings. Tells the user that they can adjust these settings now to help them through the remainder of the Setup Wizard and that they can later be changed in Settings. Displayed in Setup Wizard only. [CHAR LIMIT=none] -->
     <string name="vision_settings_description">You can customize this device to fit your needs. These accessibility features can be changed later in Settings.</string>
-    <!-- Title for the accessibility preference category of accessibility services. [CHAR LIMIT=25] -->
-    <string name="accessibility_services_title">Services</string>
+    <!-- Title for the accessibility preference category of screen reader services and settings. [CHAR LIMIT=50] -->
+    <string name="screen_reader_category_title">Screen readers</string>
+    <!-- Title for the accessibility preference category of audio services and settings. [CHAR LIMIT=50] -->
+    <string name="audio_and_captions_category_title">Audio &amp; on-screen text</string>
+    <!-- Title for the accessibility preference category of display services and settings. [CHAR LIMIT=50] -->
+    <string name="display_category_title">Display</string>
+    <!-- Title for the accessibility preference category of interaction control services and settings. [CHAR LIMIT=50] -->
+    <string name="interaction_control_category_title">Interaction controls</string>
+    <!-- Title for the accessibility preference category of services downloaded by the user. [CHAR LIMIT=50] -->
+    <string name="user_installed_services_category_title">Downloaded services</string>
     <!-- Title for the Talkback Accessibility Service. Displayed on the Accessibility Settings screen in Setup Wizard. [CHAR_LIMIT=25] -->
     <string name="talkback_title">Talkback</string>
     <!-- Summary for the Talkback Accessibility Service. Lets the user know that Talkback is a screenreader and that it is usually most helpful to blind and low vision users and whether the service is on. [CHAR_LIMIT=none] -->
     <string name="talkback_summary">Screen reader primarily for people with blindness and low vision</string>
     <!-- Summary for the Select to Speak Accessibility Service. [CHAR_LIMIT=none] -->
     <string name="select_to_speak_summary">Tap items on your screen to hear them read aloud</string>
-    <!-- Title for the accessibility preference category of system related preferences. [CHAR LIMIT=25] -->
-    <string name="accessibility_system_title">System</string>
-    <!-- Title for the accessibility preference category of display related preferences. [CHAR LIMIT=25] -->
-    <string name="accessibility_display_title">Display</string>
     <!-- Title for the accessibility preference screen to enable video captioning. [CHAR LIMIT=35] -->
     <string name="accessibility_captioning_title">Captions</string>
     <!-- Title for the accessibility preference screen to enable screen magnification. [CHAR LIMIT=35] -->
     <string name="disable_service_message">Tapping OK will
         stop <xliff:g id="service" example="TalkBack">%1$s</xliff:g>.</string>
 
-    <!-- Title for the prompt shown as a placeholder if no accessibility serivices are installed. [CHAR LIMIT=50] -->
+    <!-- Title for the prompt shown as a placeholder if no accessibility services are installed. [CHAR LIMIT=50] -->
     <string name="accessibility_no_services_installed">No services installed</string>
 
-    <!-- Default description for an accessibility serivice if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
+    <!-- Default description for an accessibility service if the latter doesn't provide one. [CHAR LIMIT=NONE] -->
     <string name="accessibility_service_default_description">No description provided.</string>
 
     <!-- Accessibility settings: button for lauching settings for an accessibility service -->
     <!-- Title for print service settings screen [CHAR LIMIT=25] -->
     <string name="print_settings_title">Print services</string>
 
-    <!-- Title for the prompt shown as a placeholder if no print serivices are installed. [CHAR LIMIT=50] -->
+    <!-- Title for the prompt shown as a placeholder if no print services are installed. [CHAR LIMIT=50] -->
     <string name="print_no_services_installed">No services installed</string>
 
     <!-- Title for the prompt shown as a placeholder if no printers are found while searching. [CHAR LIMIT=50] -->
index ee21017..478dfe5 100644 (file)
         android:title="@string/accessibility_settings"
         android:persistent="true">
 
+    <ListPreference
+            android:key="accessibility_shortcut_preference"
+            android:title="@string/accessibility_global_gesture_preference_title"/>
+
     <PreferenceCategory
-            android:key="services_category"
-            android:title="@string/accessibility_services_title">
+            android:key="user_installed_services_category"
+            android:title="@string/user_installed_services_category_title">
     </PreferenceCategory>
 
     <PreferenceCategory
-            android:key="system_category"
-            android:title="@string/accessibility_system_title">
+            android:key="screen_reader_category"
+            android:title="@string/screen_reader_category_title">
 
         <Preference
-            android:fragment="com.android.settings.accessibility.CaptionPropertiesFragment"
-            android:key="captioning_preference_screen"
-            android:title="@string/accessibility_captioning_title" />
+                android:key="tts_settings_preference"
+                android:fragment="com.android.settings.tts.TextToSpeechSettings"
+                android:title="@string/tts_settings_title"/>
+    </PreferenceCategory>
 
-        <Preference
-            android:fragment="com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment"
-            android:key="screen_magnification_preference_screen"
-            android:title="@string/accessibility_screen_magnification_title"/>
+    <PreferenceCategory
+            android:key="display_category"
+            android:title="@string/display_category_title">
 
         <Preference
-            android:fragment="com.android.settings.accessibility.ToggleFontSizePreferenceFragment"
-            android:key="font_size_preference_screen"
-            android:title="@string/title_font_size"/>
+                android:fragment="com.android.settings.accessibility.ToggleFontSizePreferenceFragment"
+                android:key="font_size_preference_screen"
+                android:title="@string/title_font_size"/>
 
         <com.android.settings.display.ScreenZoomPreference
-            android:key="screen_zoom"
-            android:title="@string/screen_zoom_title"/>
+                android:key="screen_zoom"
+                android:title="@string/screen_zoom_title"/>
 
         <Preference
-            android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
-            android:key="autoclick_preference_screen"
-            android:title="@string/accessibility_autoclick_preference_title"/>
+                android:fragment="com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment"
+                android:key="screen_magnification_preference_screen"
+                android:title="@string/accessibility_screen_magnification_title"/>
 
         <SwitchPreference
                 android:key="toggle_high_text_contrast_preference"
                 android:summary="@string/experimental_preference"/>
 
         <SwitchPreference
-                android:key="toggle_power_button_ends_call_preference"
-                android:title="@string/accessibility_power_button_ends_call_prerefence_title"
-                android:persistent="false"/>
+                android:key="toggle_inversion_preference"
+                android:title="@string/accessibility_display_inversion_preference_title"
+                android:summary="@string/accessibility_display_inversion_preference_subtitle"
+                android:persistent="false" />
 
-        <SwitchPreference
-                android:key="toggle_lock_screen_rotation_preference"
-                android:title="@string/accelerometer_title"
-                android:persistent="false"/>
+        <Preference
+                android:fragment="com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment"
+                android:key="daltonizer_preference_screen"
+                android:title="@string/accessibility_display_daltonizer_preference_title" />
 
         <SwitchPreference
                 android:key="toggle_large_pointer_icon"
                 android:title="@string/accessibility_toggle_large_pointer_icon_title" />
+    </PreferenceCategory>
+
+    <PreferenceCategory
+            android:key="interaction_control_category"
+            android:title="@string/interaction_control_category_title">
+
+        <Preference
+                android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
+                android:key="autoclick_preference_screen"
+                android:title="@string/accessibility_autoclick_preference_title"/>
 
         <SwitchPreference
-                android:key="toggle_master_mono"
-                android:title="@string/accessibility_toggle_master_mono_title"
-                android:summary="@string/accessibility_toggle_master_mono_summary"
+                android:key="toggle_power_button_ends_call_preference"
+                android:title="@string/accessibility_power_button_ends_call_prerefence_title"
                 android:persistent="false"/>
 
-        <ListPreference
-                android:key="accessibility_shortcut_preference"
-                android:title="@string/accessibility_global_gesture_preference_title"/>
-
-        <Preference
-                android:key="tts_settings_preference"
-                android:fragment="com.android.settings.tts.TextToSpeechSettings"
-                android:title="@string/tts_settings_title"/>
+        <SwitchPreference
+                android:key="toggle_lock_screen_rotation_preference"
+                android:title="@string/accelerometer_title"
+                android:persistent="false"/>
 
-        <ListPreference android:key="select_long_press_timeout_preference"
+        <ListPreference
+                android:key="select_long_press_timeout_preference"
                 android:title="@string/accessibility_long_press_timeout_preference_title"
                 android:entries="@array/long_press_timeout_selector_titles"
                 android:entryValues="@array/long_press_timeout_selector_values"
                 android:persistent="false"/>
-
     </PreferenceCategory>
 
     <PreferenceCategory
-        android:key="display_category"
-        android:title="@string/accessibility_display_title" >
+            android:key="audio_and_captions_category"
+            android:title="@string/audio_and_captions_category_title">
+
         <SwitchPreference
-            android:key="toggle_inversion_preference"
-            android:title="@string/accessibility_display_inversion_preference_title"
-            android:summary="@string/accessibility_display_inversion_preference_subtitle"
-            android:persistent="false" />
+                android:key="toggle_master_mono"
+                android:title="@string/accessibility_toggle_master_mono_title"
+                android:summary="@string/accessibility_toggle_master_mono_summary"
+                android:persistent="false"/>
+
         <Preference
-            android:fragment="com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment"
-            android:key="daltonizer_preference_screen"
-            android:title="@string/accessibility_display_daltonizer_preference_title" />
+                android:fragment="com.android.settings.accessibility.CaptionPropertiesFragment"
+                android:key="captioning_preference_screen"
+                android:title="@string/accessibility_captioning_title" />
     </PreferenceCategory>
-
 </PreferenceScreen>
index 807371e..672f4ed 100644 (file)
@@ -25,6 +25,7 @@ import android.content.DialogInterface;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -35,7 +36,9 @@ import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.ListPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -46,18 +49,17 @@ import com.android.internal.view.RotationPolicy;
 import com.android.internal.view.RotationPolicy.RotationPolicyListener;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.SingleLineSummaryPreference;
 import com.android.settings.Utils;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -68,9 +70,20 @@ import java.util.Set;
 public class AccessibilitySettings extends SettingsPreferenceFragment implements
         Preference.OnPreferenceChangeListener, Indexable {
 
+    // Index of the first preference in a preference category.
+    private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = 0;
+
     // Preference categories
-    private static final String SERVICES_CATEGORY = "services_category";
-    private static final String SYSTEM_CATEGORY = "system_category";
+    private static final String CATEGORY_SCREEN_READER = "screen_reader_category";
+    private static final String CATEGORY_AUDIO_AND_CAPTIONS = "audio_and_captions_category";
+    private static final String CATEGORY_DISPLAY = "display_category";
+    private static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
+    private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+
+    private static final String[] CATEGORIES = new String[] {
+        CATEGORY_SCREEN_READER, CATEGORY_AUDIO_AND_CAPTIONS, CATEGORY_DISPLAY,
+        CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
+    };
 
     // Preferences
     private static final String TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE =
@@ -118,10 +131,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
     // ID for dialog that confirms shortcut capabilities
     private static final int DIALOG_ID_ADD_SHORTCUT_WARNING = 1;
 
-    // Auxiliary members.
-    static final Set<ComponentName> sInstalledServices = new HashSet<>();
-
-    private final Map<String, String> mLongPressTimeoutValuetoTitleMap = new HashMap<>();
+    private final Map<String, String> mLongPressTimeoutValueToTitleMap = new HashMap<>();
 
     private final Handler mHandler = new Handler();
 
@@ -129,7 +139,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
         @Override
         public void run() {
             if (getActivity() != null) {
-                updateServicesPreferences();
+                updateServicePreferences();
             }
         }
     };
@@ -164,7 +174,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
             new SettingsContentObserver(mHandler) {
                 @Override
                 public void onChange(boolean selfChange, Uri uri) {
-                    updateServicesPreferences();
+                    updateServicePreferences();
                 }
             };
 
@@ -175,9 +185,12 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
         }
     };
 
-    // Preference controls.
-    private PreferenceCategory mServicesCategory;
-    private PreferenceCategory mSystemsCategory;
+    private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
+            new ArrayMap<>();
+    private final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap =
+            new ArrayMap<>();
+    private final Map<ComponentName, PreferenceCategory> mPreBundledServiceComponentToCategoryMap =
+            new ArrayMap<>();
 
     private SwitchPreference mToggleHighTextContrastPreference;
     private SwitchPreference mTogglePowerButtonEndsCallPreference;
@@ -260,7 +273,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
         Settings.Secure.putInt(getContentResolver(),
                 Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
         mSelectLongPressTimeoutPreference.setSummary(
-                mLongPressTimeoutValuetoTitleMap.get(stringValue));
+                mLongPressTimeoutValueToTitleMap.get(stringValue));
     }
 
     private void handleToggleInversionPreferenceChange(boolean checked) {
@@ -386,8 +399,10 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
     }
 
     private void initializeAllPreferences() {
-        mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
-        mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
+        for (int i = 0; i < CATEGORIES.length; i++) {
+            PreferenceCategory prefCategory = (PreferenceCategory) findPreference(CATEGORIES[i]);
+            mCategoryToPrefCategoryMap.put(CATEGORIES[i], prefCategory);
+        }
 
         // Text contrast.
         mToggleHighTextContrastPreference =
@@ -402,14 +417,16 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                 (SwitchPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
         if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
                 || !Utils.isVoiceCapable(getActivity())) {
-            mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
+            mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL)
+                    .removePreference(mTogglePowerButtonEndsCallPreference);
         }
 
         // Lock screen rotation.
         mToggleLockScreenRotationPreference =
                 (SwitchPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
         if (!RotationPolicy.isRotationSupported(getActivity())) {
-            mSystemsCategory.removePreference(mToggleLockScreenRotationPreference);
+            mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL)
+                    .removePreference(mToggleLockScreenRotationPreference);
         }
 
         // Large pointer icon.
@@ -424,7 +441,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
         mSelectLongPressTimeoutPreference =
                 (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
         mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
-        if (mLongPressTimeoutValuetoTitleMap.size() == 0) {
+        if (mLongPressTimeoutValueToTitleMap.size() == 0) {
             String[] timeoutValues = getResources().getStringArray(
                     R.array.long_press_timeout_selector_values);
             mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
@@ -432,7 +449,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                     R.array.long_press_timeout_selector_titles);
             final int timeoutValueCount = timeoutValues.length;
             for (int i = 0; i < timeoutValueCount; i++) {
-                mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
+                mLongPressTimeoutValueToTitleMap.put(timeoutValues[i], timeoutTitles[i]);
             }
         }
 
@@ -459,17 +476,32 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
     }
 
     private void updateAllPreferences() {
-        updateServicesPreferences();
         updateSystemPreferences();
+        updateServicePreferences();
     }
 
-    private void updateServicesPreferences() {
+    private void updateServicePreferences() {
         // Since services category is auto generated we have to do a pass
         // to generate it since services can come and go and then based on
         // the global accessibility state to decided whether it is enabled.
 
         // Generate.
-        mServicesCategory.removeAll();
+        ArrayList<Preference> servicePreferences =
+                new ArrayList<>(mServicePreferenceToPreferenceCategoryMap.keySet());
+        for (int i = 0; i < servicePreferences.size(); i++) {
+            Preference service = servicePreferences.get(i);
+            PreferenceCategory category = mServicePreferenceToPreferenceCategoryMap.get(service);
+            category.removePreference(service);
+        }
+
+        initializePreBundledServicesMapFromArray(CATEGORY_SCREEN_READER,
+                R.array.config_preinstalled_screen_reader_services);
+        initializePreBundledServicesMapFromArray(CATEGORY_AUDIO_AND_CAPTIONS,
+                R.array.config_preinstalled_audio_and_caption_services);
+        initializePreBundledServicesMapFromArray(CATEGORY_DISPLAY,
+                R.array.config_preinstalled_display_services);
+        initializePreBundledServicesMapFromArray(CATEGORY_INTERACTION_CONTROL,
+                R.array.config_preinstalled_interaction_control_services);
 
         AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
 
@@ -482,36 +514,49 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
         final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
 
+        PreferenceCategory downloadedServicesCategory =
+                mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
+        // Temporarily add the downloaded services category back if it was previously removed.
+        if (findPreference(CATEGORY_DOWNLOADED_SERVICES) == null) {
+            getPreferenceScreen().addPreference(downloadedServicesCategory);
+        }
+
         for (int i = 0, count = installedServices.size(); i < count; ++i) {
             AccessibilityServiceInfo info = installedServices.get(i);
 
-            RestrictedPreference preference =
-                    new RestrictedPreference(mServicesCategory.getContext());
+            SingleLineSummaryPreference preference =
+                    new SingleLineSummaryPreference(downloadedServicesCategory.getContext(), null);
             String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
 
+            Drawable icon = info.getResolveInfo().loadIcon(getPackageManager());
+            if (icon == null) {
+                // todo (saigem): add a default
+            }
+
             ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
-            ComponentName componentName = new ComponentName(serviceInfo.packageName,
-                    serviceInfo.name);
+            String packageName = serviceInfo.packageName;
+            ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
+            String componentNameKey = componentName.flattenToString();
 
             preference.setKey(componentName.flattenToString());
 
             preference.setTitle(title);
+            preference.setIcon(icon);
             final boolean serviceEnabled = accessibilityEnabled
                     && enabledServices.contains(componentName);
-            String serviceEnabledString;
-            if (serviceEnabled) {
-                serviceEnabledString = getString(R.string.accessibility_feature_state_on);
-            } else {
-                serviceEnabledString = getString(R.string.accessibility_feature_state_off);
-            }
+            String serviceState = serviceEnabled ?
+                    getString(R.string.accessibility_feature_state_on) :
+                    getString(R.string.accessibility_feature_state_off);
+            String serviceSummary = info.loadSummary(getPackageManager());
+            serviceSummary = (TextUtils.isEmpty(serviceSummary)) ? serviceState.toUpperCase() :
+                    serviceState.toUpperCase() + " / " + serviceSummary;
 
             // Disable all accessibility services that are not permitted.
-            String packageName = serviceInfo.packageName;
             boolean serviceAllowed =
                     permittedServices == null || permittedServices.contains(packageName);
             if (!serviceAllowed && !serviceEnabled) {
                 EnforcedAdmin admin = RestrictedLockUtils.checkIfAccessibilityServiceDisallowed(
-                        getActivity(), serviceInfo.packageName, UserHandle.myUserId());
+                        getActivity(), packageName, UserHandle.myUserId());
                 if (admin != null) {
                     preference.setDisabledByAdmin(admin);
                 } else {
@@ -521,9 +566,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                 preference.setEnabled(true);
             }
 
-            preference.setSummary(serviceEnabledString);
-
-            preference.setOrder(i);
+            preference.setSummary(serviceSummary);
             preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
             preference.setPersistent(true);
 
@@ -543,26 +586,33 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                 extras.putString(EXTRA_SETTINGS_TITLE,
                         getString(R.string.accessibility_menu_item_settings));
                 extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
-                        new ComponentName(info.getResolveInfo().serviceInfo.packageName,
-                                settingsClassName).flattenToString());
+                        new ComponentName(packageName, settingsClassName).flattenToString());
             }
-
             extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
 
-            mServicesCategory.addPreference(preference);
+            PreferenceCategory prefCategory = downloadedServicesCategory;
+            // Set the appropriate category if the service comes pre-installed.
+            if (mPreBundledServiceComponentToCategoryMap.containsKey(componentName)) {
+                prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName);
+            }
+            preference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
+            prefCategory.addPreference(preference);
+            mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory);
         }
 
-        if (mServicesCategory.getPreferenceCount() == 0) {
-            if (mNoServicesMessagePreference == null) {
-                mNoServicesMessagePreference = new Preference(getPrefContext());
-                mNoServicesMessagePreference.setPersistent(false);
-                mNoServicesMessagePreference.setLayoutResource(
-                        R.layout.text_description_preference);
-                mNoServicesMessagePreference.setSelectable(false);
-                mNoServicesMessagePreference.setSummary(
-                        getString(R.string.accessibility_no_services_installed));
-            }
-            mServicesCategory.addPreference(mNoServicesMessagePreference);
+        // If the user has not installed any additional services, hide the category.
+        if (downloadedServicesCategory.getPreferenceCount() == 0) {
+            PreferenceScreen screen = getPreferenceScreen();
+            screen.removePreference(downloadedServicesCategory);
+        }
+    }
+
+    private void initializePreBundledServicesMapFromArray(String categoryKey, int key) {
+        String[] services = getResources().getStringArray(key);
+        PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey);
+        for (int i = 0; i < services.length; i++) {
+            ComponentName component = ComponentName.unflattenFromString(services[i]);
+            mPreBundledServiceComponentToCategoryMap.put(component, category);
         }
     }
 
@@ -602,7 +652,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
                 Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
         String value = String.valueOf(longPressTimeout);
         mSelectLongPressTimeoutPreference.setValue(value);
-        mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
+        mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValueToTitleMap.get(value));
 
         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
                 mCaptioningPreferenceScreen);