1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.accessibility; 18 19 import android.accessibilityservice.AccessibilityServiceInfo; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.pm.ServiceInfo; 24 import android.content.res.Resources; 25 import android.graphics.drawable.Drawable; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.UserHandle; 30 import android.provider.SearchIndexableResource; 31 import android.provider.Settings; 32 import android.support.v14.preference.SwitchPreference; 33 import android.support.v4.content.ContextCompat; 34 import android.support.v7.preference.ListPreference; 35 import android.support.v7.preference.Preference; 36 import android.support.v7.preference.PreferenceCategory; 37 import android.support.v7.preference.PreferenceScreen; 38 import android.text.TextUtils; 39 import android.util.ArrayMap; 40 import android.view.KeyCharacterMap; 41 import android.view.KeyEvent; 42 import android.view.accessibility.AccessibilityManager; 43 44 import com.android.internal.content.PackageMonitor; 45 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 46 import com.android.internal.view.RotationPolicy; 47 import com.android.internal.view.RotationPolicy.RotationPolicyListener; 48 import com.android.settings.DisplaySettings; 49 import com.android.settings.R; 50 import com.android.settings.SettingsPreferenceFragment; 51 import com.android.settings.Utils; 52 import com.android.settings.search.BaseSearchIndexProvider; 53 import com.android.settings.search.Indexable; 54 import com.android.settingslib.RestrictedLockUtils; 55 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 56 import com.android.settingslib.RestrictedPreference; 57 import com.android.settingslib.accessibility.AccessibilityUtils; 58 59 import java.util.ArrayList; 60 import java.util.HashMap; 61 import java.util.List; 62 import java.util.Map; 63 import java.util.Set; 64 65 /** 66 * Activity with the accessibility settings. 67 */ 68 public class AccessibilitySettings extends SettingsPreferenceFragment implements 69 Preference.OnPreferenceChangeListener, Indexable { 70 71 // Index of the first preference in a preference category. 72 private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1; 73 74 // Preference categories 75 private static final String CATEGORY_SCREEN_READER = "screen_reader_category"; 76 private static final String CATEGORY_AUDIO_AND_CAPTIONS = "audio_and_captions_category"; 77 private static final String CATEGORY_DISPLAY = "display_category"; 78 private static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category"; 79 private static final String CATEGORY_EXPERIMENTAL = "experimental_category"; 80 private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category"; 81 82 private static final String[] CATEGORIES = new String[] { 83 CATEGORY_SCREEN_READER, CATEGORY_AUDIO_AND_CAPTIONS, CATEGORY_DISPLAY, 84 CATEGORY_INTERACTION_CONTROL, CATEGORY_EXPERIMENTAL, CATEGORY_DOWNLOADED_SERVICES 85 }; 86 87 // Preferences 88 private static final String TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE = 89 "toggle_high_text_contrast_preference"; 90 private static final String TOGGLE_INVERSION_PREFERENCE = 91 "toggle_inversion_preference"; 92 private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE = 93 "toggle_power_button_ends_call_preference"; 94 private static final String TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE = 95 "toggle_lock_screen_rotation_preference"; 96 private static final String TOGGLE_LARGE_POINTER_ICON = 97 "toggle_large_pointer_icon"; 98 private static final String TOGGLE_MASTER_MONO = 99 "toggle_master_mono"; 100 private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE = 101 "select_long_press_timeout_preference"; 102 private static final String ACCESSIBILITY_SHORTCUT_PREFERENCE = 103 "accessibility_shortcut_preference"; 104 private static final String CAPTIONING_PREFERENCE_SCREEN = 105 "captioning_preference_screen"; 106 private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN = 107 "magnification_preference_screen"; 108 private static final String FONT_SIZE_PREFERENCE_SCREEN = 109 "font_size_preference_screen"; 110 private static final String AUTOCLICK_PREFERENCE_SCREEN = 111 "autoclick_preference_screen"; 112 private static final String DISPLAY_DALTONIZER_PREFERENCE_SCREEN = 113 "daltonizer_preference_screen"; 114 115 // Extras passed to sub-fragments. 116 static final String EXTRA_PREFERENCE_KEY = "preference_key"; 117 static final String EXTRA_CHECKED = "checked"; 118 static final String EXTRA_TITLE = "title"; 119 static final String EXTRA_SUMMARY = "summary"; 120 static final String EXTRA_SETTINGS_TITLE = "settings_title"; 121 static final String EXTRA_COMPONENT_NAME = "component_name"; 122 static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name"; 123 static final String EXTRA_VIDEO_RAW_RESOURCE_ID = "video_resource"; 124 static final String EXTRA_LAUNCHED_FROM_SUW = "from_suw"; 125 126 // Timeout before we update the services if packages are added/removed 127 // since the AccessibilityManagerService has to do that processing first 128 // to generate the AccessibilityServiceInfo we need for proper 129 // presentation. 130 private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000; 131 132 private final Map<String, String> mLongPressTimeoutValueToTitleMap = new HashMap<>(); 133 134 private final Handler mHandler = new Handler(); 135 136 private final Runnable mUpdateRunnable = new Runnable() { 137 @Override 138 public void run() { 139 if (getActivity() != null) { 140 updateServicePreferences(); 141 } 142 } 143 }; 144 145 private final PackageMonitor mSettingsPackageMonitor = new PackageMonitor() { 146 @Override 147 public void onPackageAdded(String packageName, int uid) { 148 sendUpdate(); 149 } 150 151 @Override 152 public void onPackageAppeared(String packageName, int reason) { 153 sendUpdate(); 154 } 155 156 @Override 157 public void onPackageDisappeared(String packageName, int reason) { 158 sendUpdate(); 159 } 160 161 @Override 162 public void onPackageRemoved(String packageName, int uid) { 163 sendUpdate(); 164 } 165 166 private void sendUpdate() { 167 mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_SERVICES_MILLIS); 168 } 169 }; 170 171 private final SettingsContentObserver mSettingsContentObserver = 172 new SettingsContentObserver(mHandler) { 173 @Override 174 public void onChange(boolean selfChange, Uri uri) { 175 updateServicePreferences(); 176 } 177 }; 178 179 private final RotationPolicyListener mRotationPolicyListener = new RotationPolicyListener() { 180 @Override 181 public void onChange() { 182 updateLockScreenRotationCheckbox(); 183 } 184 }; 185 186 private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap = 187 new ArrayMap<>(); 188 private final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap = 189 new ArrayMap<>(); 190 private final Map<ComponentName, PreferenceCategory> mPreBundledServiceComponentToCategoryMap = 191 new ArrayMap<>(); 192 193 private SwitchPreference mToggleHighTextContrastPreference; 194 private SwitchPreference mTogglePowerButtonEndsCallPreference; 195 private SwitchPreference mToggleLockScreenRotationPreference; 196 private SwitchPreference mToggleLargePointerIconPreference; 197 private SwitchPreference mToggleMasterMonoPreference; 198 private ListPreference mSelectLongPressTimeoutPreference; 199 private Preference mNoServicesMessagePreference; 200 private Preference mCaptioningPreferenceScreen; 201 private Preference mDisplayMagnificationPreferenceScreen; 202 private Preference mFontSizePreferenceScreen; 203 private Preference mAutoclickPreferenceScreen; 204 private Preference mAccessibilityShortcutPreferenceScreen; 205 private Preference mDisplayDaltonizerPreferenceScreen; 206 private SwitchPreference mToggleInversionPreference; 207 208 private int mLongPressTimeoutDefault; 209 210 private DevicePolicyManager mDpm; 211 212 /** 213 * Check if the color transforms are color accelerated. Some transforms are experimental only 214 * on non-accelerated platforms due to the performance implications. 215 * 216 * @param context The current context 217 * @return 218 */ isColorTransformAccelerated(Context context)219 public static boolean isColorTransformAccelerated(Context context) { 220 return context.getResources() 221 .getBoolean(com.android.internal.R.bool.config_setColorTransformAccelerated); 222 } 223 224 @Override getMetricsCategory()225 public int getMetricsCategory() { 226 return MetricsEvent.ACCESSIBILITY; 227 } 228 229 @Override getHelpResource()230 protected int getHelpResource() { 231 return R.string.help_uri_accessibility; 232 } 233 234 @Override onCreate(Bundle icicle)235 public void onCreate(Bundle icicle) { 236 super.onCreate(icicle); 237 addPreferencesFromResource(R.xml.accessibility_settings); 238 initializeAllPreferences(); 239 mDpm = (DevicePolicyManager) (getActivity() 240 .getSystemService(Context.DEVICE_POLICY_SERVICE)); 241 } 242 243 @Override onResume()244 public void onResume() { 245 super.onResume(); 246 updateAllPreferences(); 247 248 mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false); 249 mSettingsContentObserver.register(getContentResolver()); 250 if (RotationPolicy.isRotationSupported(getActivity())) { 251 RotationPolicy.registerRotationPolicyListener(getActivity(), 252 mRotationPolicyListener); 253 } 254 } 255 256 @Override onPause()257 public void onPause() { 258 mSettingsPackageMonitor.unregister(); 259 mSettingsContentObserver.unregister(getContentResolver()); 260 if (RotationPolicy.isRotationSupported(getActivity())) { 261 RotationPolicy.unregisterRotationPolicyListener(getActivity(), 262 mRotationPolicyListener); 263 } 264 super.onPause(); 265 } 266 267 @Override onPreferenceChange(Preference preference, Object newValue)268 public boolean onPreferenceChange(Preference preference, Object newValue) { 269 if (mSelectLongPressTimeoutPreference == preference) { 270 handleLongPressTimeoutPreferenceChange((String) newValue); 271 return true; 272 } else if (mToggleInversionPreference == preference) { 273 handleToggleInversionPreferenceChange((Boolean) newValue); 274 return true; 275 } 276 return false; 277 } 278 handleLongPressTimeoutPreferenceChange(String stringValue)279 private void handleLongPressTimeoutPreferenceChange(String stringValue) { 280 Settings.Secure.putInt(getContentResolver(), 281 Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue)); 282 mSelectLongPressTimeoutPreference.setSummary( 283 mLongPressTimeoutValueToTitleMap.get(stringValue)); 284 } 285 handleToggleInversionPreferenceChange(boolean checked)286 private void handleToggleInversionPreferenceChange(boolean checked) { 287 Settings.Secure.putInt(getContentResolver(), 288 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, (checked ? 1 : 0)); 289 } 290 291 @Override onPreferenceTreeClick(Preference preference)292 public boolean onPreferenceTreeClick(Preference preference) { 293 if (mToggleHighTextContrastPreference == preference) { 294 handleToggleTextContrastPreferenceClick(); 295 return true; 296 } else if (mTogglePowerButtonEndsCallPreference == preference) { 297 handleTogglePowerButtonEndsCallPreferenceClick(); 298 return true; 299 } else if (mToggleLockScreenRotationPreference == preference) { 300 handleLockScreenRotationPreferenceClick(); 301 return true; 302 } else if (mToggleLargePointerIconPreference == preference) { 303 handleToggleLargePointerIconPreferenceClick(); 304 return true; 305 } else if (mToggleMasterMonoPreference == preference) { 306 handleToggleMasterMonoPreferenceClick(); 307 return true; 308 } 309 return super.onPreferenceTreeClick(preference); 310 } 311 handleToggleTextContrastPreferenceClick()312 private void handleToggleTextContrastPreferenceClick() { 313 Settings.Secure.putInt(getContentResolver(), 314 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 315 (mToggleHighTextContrastPreference.isChecked() ? 1 : 0)); 316 } 317 handleTogglePowerButtonEndsCallPreferenceClick()318 private void handleTogglePowerButtonEndsCallPreferenceClick() { 319 Settings.Secure.putInt(getContentResolver(), 320 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, 321 (mTogglePowerButtonEndsCallPreference.isChecked() 322 ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP 323 : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF)); 324 } 325 handleLockScreenRotationPreferenceClick()326 private void handleLockScreenRotationPreferenceClick() { 327 RotationPolicy.setRotationLockForAccessibility(getActivity(), 328 !mToggleLockScreenRotationPreference.isChecked()); 329 } 330 handleToggleLargePointerIconPreferenceClick()331 private void handleToggleLargePointerIconPreferenceClick() { 332 Settings.Secure.putInt(getContentResolver(), 333 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 334 mToggleLargePointerIconPreference.isChecked() ? 1 : 0); 335 } 336 handleToggleMasterMonoPreferenceClick()337 private void handleToggleMasterMonoPreferenceClick() { 338 Settings.System.putIntForUser(getContentResolver(), Settings.System.MASTER_MONO, 339 mToggleMasterMonoPreference.isChecked() ? 1 : 0, UserHandle.USER_CURRENT); 340 } 341 initializeAllPreferences()342 private void initializeAllPreferences() { 343 for (int i = 0; i < CATEGORIES.length; i++) { 344 PreferenceCategory prefCategory = (PreferenceCategory) findPreference(CATEGORIES[i]); 345 mCategoryToPrefCategoryMap.put(CATEGORIES[i], prefCategory); 346 } 347 348 // Text contrast. 349 mToggleHighTextContrastPreference = 350 (SwitchPreference) findPreference(TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE); 351 352 // Display inversion. 353 mToggleInversionPreference = (SwitchPreference) findPreference(TOGGLE_INVERSION_PREFERENCE); 354 mToggleInversionPreference.setOnPreferenceChangeListener(this); 355 356 // Power button ends calls. 357 mTogglePowerButtonEndsCallPreference = 358 (SwitchPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE); 359 if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER) 360 || !Utils.isVoiceCapable(getActivity())) { 361 mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL) 362 .removePreference(mTogglePowerButtonEndsCallPreference); 363 } 364 365 // Lock screen rotation. 366 mToggleLockScreenRotationPreference = 367 (SwitchPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE); 368 if (!RotationPolicy.isRotationSupported(getActivity())) { 369 mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL) 370 .removePreference(mToggleLockScreenRotationPreference); 371 } 372 373 // Large pointer icon. 374 mToggleLargePointerIconPreference = 375 (SwitchPreference) findPreference(TOGGLE_LARGE_POINTER_ICON); 376 377 // Master Mono 378 mToggleMasterMonoPreference = 379 (SwitchPreference) findPreference(TOGGLE_MASTER_MONO); 380 381 // Long press timeout. 382 mSelectLongPressTimeoutPreference = 383 (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE); 384 mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this); 385 if (mLongPressTimeoutValueToTitleMap.size() == 0) { 386 String[] timeoutValues = getResources().getStringArray( 387 R.array.long_press_timeout_selector_values); 388 mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]); 389 String[] timeoutTitles = getResources().getStringArray( 390 R.array.long_press_timeout_selector_titles); 391 final int timeoutValueCount = timeoutValues.length; 392 for (int i = 0; i < timeoutValueCount; i++) { 393 mLongPressTimeoutValueToTitleMap.put(timeoutValues[i], timeoutTitles[i]); 394 } 395 } 396 397 // Captioning. 398 mCaptioningPreferenceScreen = findPreference(CAPTIONING_PREFERENCE_SCREEN); 399 400 // Display magnification. 401 mDisplayMagnificationPreferenceScreen = findPreference( 402 DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN); 403 configureMagnificationPreferenceIfNeeded(mDisplayMagnificationPreferenceScreen); 404 405 // Font size. 406 mFontSizePreferenceScreen = findPreference(FONT_SIZE_PREFERENCE_SCREEN); 407 408 // Autoclick after pointer stops. 409 mAutoclickPreferenceScreen = findPreference(AUTOCLICK_PREFERENCE_SCREEN); 410 411 // Display color adjustments. 412 mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN); 413 414 // Accessibility shortcut 415 mAccessibilityShortcutPreferenceScreen = findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE); 416 } 417 updateAllPreferences()418 private void updateAllPreferences() { 419 updateSystemPreferences(); 420 updateServicePreferences(); 421 } 422 updateServicePreferences()423 private void updateServicePreferences() { 424 // Since services category is auto generated we have to do a pass 425 // to generate it since services can come and go and then based on 426 // the global accessibility state to decided whether it is enabled. 427 428 // Generate. 429 ArrayList<Preference> servicePreferences = 430 new ArrayList<>(mServicePreferenceToPreferenceCategoryMap.keySet()); 431 for (int i = 0; i < servicePreferences.size(); i++) { 432 Preference service = servicePreferences.get(i); 433 PreferenceCategory category = mServicePreferenceToPreferenceCategoryMap.get(service); 434 category.removePreference(service); 435 } 436 437 initializePreBundledServicesMapFromArray(CATEGORY_SCREEN_READER, 438 R.array.config_preinstalled_screen_reader_services); 439 initializePreBundledServicesMapFromArray(CATEGORY_AUDIO_AND_CAPTIONS, 440 R.array.config_preinstalled_audio_and_caption_services); 441 initializePreBundledServicesMapFromArray(CATEGORY_DISPLAY, 442 R.array.config_preinstalled_display_services); 443 initializePreBundledServicesMapFromArray(CATEGORY_INTERACTION_CONTROL, 444 R.array.config_preinstalled_interaction_control_services); 445 446 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity()); 447 448 List<AccessibilityServiceInfo> installedServices = 449 accessibilityManager.getInstalledAccessibilityServiceList(); 450 Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings( 451 getActivity()); 452 List<String> permittedServices = mDpm.getPermittedAccessibilityServices( 453 UserHandle.myUserId()); 454 final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(), 455 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; 456 457 PreferenceCategory downloadedServicesCategory = 458 mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES); 459 // Temporarily add the downloaded services category back if it was previously removed. 460 if (findPreference(CATEGORY_DOWNLOADED_SERVICES) == null) { 461 getPreferenceScreen().addPreference(downloadedServicesCategory); 462 } 463 464 for (int i = 0, count = installedServices.size(); i < count; ++i) { 465 AccessibilityServiceInfo info = installedServices.get(i); 466 467 RestrictedPreference preference = 468 new RestrictedPreference(downloadedServicesCategory.getContext()); 469 String title = info.getResolveInfo().loadLabel(getPackageManager()).toString(); 470 471 Drawable icon; 472 if (info.getResolveInfo().getIconResource() == 0) { 473 icon = ContextCompat.getDrawable(getContext(), R.mipmap.ic_accessibility_generic); 474 } else { 475 icon = info.getResolveInfo().loadIcon(getPackageManager()); 476 } 477 478 ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo; 479 String packageName = serviceInfo.packageName; 480 ComponentName componentName = new ComponentName(packageName, serviceInfo.name); 481 String componentNameKey = componentName.flattenToString(); 482 483 preference.setKey(componentName.flattenToString()); 484 485 preference.setTitle(title); 486 preference.setIcon(icon); 487 final boolean serviceEnabled = accessibilityEnabled 488 && enabledServices.contains(componentName); 489 final String serviceState = serviceEnabled ? 490 getString(R.string.accessibility_summary_state_enabled) : 491 getString(R.string.accessibility_summary_state_disabled); 492 final CharSequence serviceSummary = info.loadSummary(getPackageManager()); 493 final String stateSummaryCombo = getString( 494 R.string.preference_summary_default_combination, 495 serviceState, serviceSummary); 496 preference.setSummary((TextUtils.isEmpty(serviceSummary)) ? serviceState 497 : stateSummaryCombo); 498 499 // Disable all accessibility services that are not permitted. 500 boolean serviceAllowed = 501 permittedServices == null || permittedServices.contains(packageName); 502 if (!serviceAllowed && !serviceEnabled) { 503 EnforcedAdmin admin = RestrictedLockUtils.checkIfAccessibilityServiceDisallowed( 504 getActivity(), packageName, UserHandle.myUserId()); 505 if (admin != null) { 506 preference.setDisabledByAdmin(admin); 507 } else { 508 preference.setEnabled(false); 509 } 510 } else { 511 preference.setEnabled(true); 512 } 513 514 preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName()); 515 preference.setPersistent(true); 516 517 Bundle extras = preference.getExtras(); 518 extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey()); 519 extras.putBoolean(EXTRA_CHECKED, serviceEnabled); 520 extras.putString(EXTRA_TITLE, title); 521 522 String description = info.loadDescription(getPackageManager()); 523 if (TextUtils.isEmpty(description)) { 524 description = getString(R.string.accessibility_service_default_description); 525 } 526 extras.putString(EXTRA_SUMMARY, description); 527 528 String settingsClassName = info.getSettingsActivityName(); 529 if (!TextUtils.isEmpty(settingsClassName)) { 530 extras.putString(EXTRA_SETTINGS_TITLE, 531 getString(R.string.accessibility_menu_item_settings)); 532 extras.putString(EXTRA_SETTINGS_COMPONENT_NAME, 533 new ComponentName(packageName, settingsClassName).flattenToString()); 534 } 535 extras.putParcelable(EXTRA_COMPONENT_NAME, componentName); 536 537 PreferenceCategory prefCategory = downloadedServicesCategory; 538 // Set the appropriate category if the service comes pre-installed. 539 if (mPreBundledServiceComponentToCategoryMap.containsKey(componentName)) { 540 prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName); 541 } 542 preference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX); 543 prefCategory.addPreference(preference); 544 mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory); 545 } 546 547 // If the user has not installed any additional services, hide the category. 548 if (downloadedServicesCategory.getPreferenceCount() == 0) { 549 PreferenceScreen screen = getPreferenceScreen(); 550 screen.removePreference(downloadedServicesCategory); 551 } 552 } 553 initializePreBundledServicesMapFromArray(String categoryKey, int key)554 private void initializePreBundledServicesMapFromArray(String categoryKey, int key) { 555 String[] services = getResources().getStringArray(key); 556 PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); 557 for (int i = 0; i < services.length; i++) { 558 ComponentName component = ComponentName.unflattenFromString(services[i]); 559 mPreBundledServiceComponentToCategoryMap.put(component, category); 560 } 561 } 562 updateSystemPreferences()563 private void updateSystemPreferences() { 564 // Move color inversion and color correction preferences to Display category if device 565 // supports HWC hardware-accelerated color transform. 566 if (isColorTransformAccelerated(getContext())) { 567 PreferenceCategory experimentalCategory = 568 mCategoryToPrefCategoryMap.get(CATEGORY_EXPERIMENTAL); 569 PreferenceCategory displayCategory = 570 mCategoryToPrefCategoryMap.get(CATEGORY_DISPLAY); 571 experimentalCategory.removePreference(mToggleInversionPreference); 572 experimentalCategory.removePreference(mDisplayDaltonizerPreferenceScreen); 573 mToggleInversionPreference.setOrder(mToggleLargePointerIconPreference.getOrder()); 574 mDisplayDaltonizerPreferenceScreen.setOrder(mToggleInversionPreference.getOrder()); 575 mToggleInversionPreference.setSummary(R.string.summary_empty); 576 displayCategory.addPreference(mToggleInversionPreference); 577 displayCategory.addPreference(mDisplayDaltonizerPreferenceScreen); 578 } 579 580 // Text contrast. 581 mToggleHighTextContrastPreference.setChecked( 582 Settings.Secure.getInt(getContentResolver(), 583 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0) == 1); 584 585 // If the quick setting is enabled, the preference MUST be enabled. 586 mToggleInversionPreference.setChecked(Settings.Secure.getInt(getContentResolver(), 587 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0) == 1); 588 589 // Power button ends calls. 590 if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER) 591 && Utils.isVoiceCapable(getActivity())) { 592 final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(), 593 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, 594 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT); 595 final boolean powerButtonEndsCall = 596 (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP); 597 mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall); 598 } 599 600 // Auto-rotate screen 601 updateLockScreenRotationCheckbox(); 602 603 // Large pointer icon. 604 mToggleLargePointerIconPreference.setChecked(Settings.Secure.getInt(getContentResolver(), 605 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 0) != 0); 606 607 // Master mono 608 updateMasterMono(); 609 610 // Long press timeout. 611 final int longPressTimeout = Settings.Secure.getInt(getContentResolver(), 612 Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault); 613 String value = String.valueOf(longPressTimeout); 614 mSelectLongPressTimeoutPreference.setValue(value); 615 mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValueToTitleMap.get(value)); 616 617 updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, 618 mCaptioningPreferenceScreen); 619 updateFeatureSummary(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 620 mDisplayDaltonizerPreferenceScreen); 621 622 updateMagnificationSummary(mDisplayMagnificationPreferenceScreen); 623 624 updateFontSizeSummary(mFontSizePreferenceScreen); 625 626 updateAutoclickSummary(mAutoclickPreferenceScreen); 627 628 updateAccessibilityShortcut(mAccessibilityShortcutPreferenceScreen); 629 } 630 updateMagnificationSummary(Preference pref)631 private void updateMagnificationSummary(Preference pref) { 632 final boolean tripleTapEnabled = Settings.Secure.getInt(getContentResolver(), 633 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1; 634 final boolean buttonEnabled = Settings.Secure.getInt(getContentResolver(), 635 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1; 636 637 int summaryResId = 0; 638 if (!tripleTapEnabled && !buttonEnabled) { 639 summaryResId = R.string.accessibility_feature_state_off; 640 } else if (!tripleTapEnabled && buttonEnabled) { 641 summaryResId = R.string.accessibility_screen_magnification_navbar_title; 642 } else if (tripleTapEnabled && !buttonEnabled) { 643 summaryResId = R.string.accessibility_screen_magnification_gestures_title; 644 } else { 645 summaryResId = R.string.accessibility_screen_magnification_state_navbar_gesture; 646 } 647 pref.setSummary(summaryResId); 648 } 649 updateFeatureSummary(String prefKey, Preference pref)650 private void updateFeatureSummary(String prefKey, Preference pref) { 651 final boolean enabled = Settings.Secure.getInt(getContentResolver(), prefKey, 0) == 1; 652 pref.setSummary(enabled ? R.string.accessibility_feature_state_on 653 : R.string.accessibility_feature_state_off); 654 } 655 updateAutoclickSummary(Preference pref)656 private void updateAutoclickSummary(Preference pref) { 657 final boolean enabled = Settings.Secure.getInt( 658 getContentResolver(), Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, 0) == 1; 659 if (!enabled) { 660 pref.setSummary(R.string.accessibility_feature_state_off); 661 return; 662 } 663 int delay = Settings.Secure.getInt( 664 getContentResolver(), Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, 665 AccessibilityManager.AUTOCLICK_DELAY_DEFAULT); 666 pref.setSummary(ToggleAutoclickPreferenceFragment.getAutoclickPreferenceSummary( 667 getResources(), delay)); 668 } 669 updateFontSizeSummary(Preference pref)670 private void updateFontSizeSummary(Preference pref) { 671 final float currentScale = Settings.System.getFloat(getContext().getContentResolver(), 672 Settings.System.FONT_SCALE, 1.0f); 673 final Resources res = getContext().getResources(); 674 final String[] entries = res.getStringArray(R.array.entries_font_size); 675 final String[] strEntryValues = res.getStringArray(R.array.entryvalues_font_size); 676 final int index = ToggleFontSizePreferenceFragment.fontSizeValueToIndex(currentScale, 677 strEntryValues); 678 pref.setSummary(entries[index]); 679 } 680 updateLockScreenRotationCheckbox()681 private void updateLockScreenRotationCheckbox() { 682 Context context = getActivity(); 683 if (context != null) { 684 mToggleLockScreenRotationPreference.setChecked( 685 !RotationPolicy.isRotationLocked(context)); 686 } 687 } 688 updateMasterMono()689 private void updateMasterMono() { 690 final boolean masterMono = Settings.System.getIntForUser( 691 getContentResolver(), Settings.System.MASTER_MONO, 692 0 /* default */, UserHandle.USER_CURRENT) == 1; 693 mToggleMasterMonoPreference.setChecked(masterMono); 694 } 695 updateAccessibilityShortcut(Preference preference)696 private void updateAccessibilityShortcut(Preference preference) { 697 if (AccessibilityManager.getInstance(getActivity()) 698 .getInstalledAccessibilityServiceList().isEmpty()) { 699 mAccessibilityShortcutPreferenceScreen 700 .setSummary(getString(R.string.accessibility_no_services_installed)); 701 mAccessibilityShortcutPreferenceScreen.setEnabled(false); 702 } else { 703 mAccessibilityShortcutPreferenceScreen.setEnabled(true); 704 boolean shortcutEnabled = 705 AccessibilityUtils.isShortcutEnabled(getContext(), UserHandle.myUserId()); 706 CharSequence summary = shortcutEnabled 707 ? AccessibilityShortcutPreferenceFragment.getServiceName(getContext()) 708 : getString(R.string.accessibility_feature_state_off); 709 mAccessibilityShortcutPreferenceScreen.setSummary(summary); 710 } 711 } 712 configureMagnificationPreferenceIfNeeded(Preference preference)713 private static void configureMagnificationPreferenceIfNeeded(Preference preference) { 714 // Some devices support only a single magnification mode. In these cases, we redirect to 715 // the magnification mode's UI directly, rather than showing a PreferenceScreen with a 716 // single list item. 717 final Context context = preference.getContext(); 718 if (!MagnificationPreferenceFragment.isApplicable(context.getResources())) { 719 preference.setFragment(ToggleScreenMagnificationPreferenceFragment.class.getName()); 720 final Bundle extras = preference.getExtras(); 721 MagnificationPreferenceFragment.populateMagnificationGesturesPreferenceExtras(extras, 722 context); 723 } 724 } 725 726 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 727 new BaseSearchIndexProvider() { 728 729 @Override 730 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, 731 boolean enabled) { 732 List<SearchIndexableResource> indexables = new ArrayList<>(); 733 SearchIndexableResource indexable = new SearchIndexableResource(context); 734 indexable.xmlResId = R.xml.accessibility_settings; 735 indexables.add(indexable); 736 return indexables; 737 } 738 739 @Override 740 public List<String> getNonIndexableKeys(Context context) { 741 List<String> keys = super.getNonIndexableKeys(context); 742 // Duplicates in Display 743 keys.add(FONT_SIZE_PREFERENCE_SCREEN); 744 keys.add(DisplaySettings.KEY_DISPLAY_SIZE); 745 746 return keys; 747 } 748 }; 749 } 750