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