diff --git a/res/values/config.xml b/res/values/config.xml index 0fa2b71dad4..f81bf9b3e38 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -67,4 +67,36 @@ false + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 1e1304e893f..6f2898dc112 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3974,18 +3974,22 @@ Vision Settings You can customize this device to fit your needs. These accessibility features can be changed later in Settings. - - Services + + Screen readers + + Audio & on-screen text + + Display + + Interaction controls + + Downloaded services Talkback Screen reader primarily for people with blindness and low vision Tap items on your screen to hear them read aloud - - System - - Display Captions @@ -4176,10 +4180,10 @@ Tapping OK will stop %1$s. - + No services installed - + No description provided. @@ -4200,7 +4204,7 @@ Print services - + No services installed diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml index ee21017e1de..478dfe5be78 100644 --- a/res/xml/accessibility_settings.xml +++ b/res/xml/accessibility_settings.xml @@ -18,44 +18,73 @@ android:title="@string/accessibility_settings" android:persistent="true"> + + + android:key="user_installed_services_category" + android:title="@string/user_installed_services_category_title"> + android:key="screen_reader_category" + android:title="@string/screen_reader_category_title"> + android:key="tts_settings_preference" + android:fragment="com.android.settings.tts.TextToSpeechSettings" + android:title="@string/tts_settings_title"/> + + + - - + android:fragment="com.android.settings.accessibility.ToggleFontSizePreferenceFragment" + android:key="font_size_preference_screen" + android:title="@string/title_font_size"/> + android:key="screen_zoom" + android:title="@string/screen_zoom_title"/> + android:fragment="com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment" + android:key="screen_magnification_preference_screen" + android:title="@string/accessibility_screen_magnification_title"/> + + + + + + + + + + + - + + + + - - - - - + android:fragment="com.android.settings.accessibility.CaptionPropertiesFragment" + android:key="captioning_preference_screen" + android:title="@string/accessibility_captioning_title" /> - - - - - - diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 807371ea278..672f4ed8647 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -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 sInstalledServices = new HashSet<>(); - - private final Map mLongPressTimeoutValuetoTitleMap = new HashMap<>(); + private final Map 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 mCategoryToPrefCategoryMap = + new ArrayMap<>(); + private final Map mServicePreferenceToPreferenceCategoryMap = + new ArrayMap<>(); + private final Map 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 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);