1 /* 2 * Copyright (C) 2013 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 static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; 20 import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums; 21 import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; 22 import static com.android.settings.accessibility.AccessibilityUtil.State.ON; 23 24 import android.app.Dialog; 25 import android.app.settings.SettingsEnums; 26 import android.content.ComponentName; 27 import android.content.ContentResolver; 28 import android.content.Context; 29 import android.content.DialogInterface; 30 import android.content.pm.PackageManager; 31 import android.icu.text.CaseMap; 32 import android.icu.text.MessageFormat; 33 import android.net.Uri; 34 import android.os.Bundle; 35 import android.provider.DeviceConfig; 36 import android.provider.Settings; 37 import android.text.TextUtils; 38 import android.view.LayoutInflater; 39 import android.view.View; 40 import android.view.ViewGroup; 41 import android.view.accessibility.AccessibilityManager; 42 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener; 43 import android.widget.CheckBox; 44 45 import androidx.preference.Preference; 46 import androidx.preference.PreferenceCategory; 47 import androidx.preference.SwitchPreference; 48 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.settings.DialogCreatable; 51 import com.android.settings.R; 52 import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType; 53 import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; 54 import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; 55 import com.android.settings.utils.LocaleUtils; 56 import com.android.settingslib.core.AbstractPreferenceController; 57 58 import com.google.android.setupcompat.util.WizardManagerHelper; 59 60 import java.util.ArrayList; 61 import java.util.List; 62 import java.util.Locale; 63 import java.util.StringJoiner; 64 65 /** 66 * Fragment that shows the actual UI for providing basic magnification accessibility service setup 67 * and does not have toggle bar to turn on service to use. 68 */ 69 public class ToggleScreenMagnificationPreferenceFragment extends 70 ToggleFeaturePreferenceFragment implements 71 MagnificationModePreferenceController.DialogHelper { 72 73 private static final String TAG = "ToggleScreenMagnificationPreferenceFragment"; 74 private static final char COMPONENT_NAME_SEPARATOR = ':'; 75 private static final TextUtils.SimpleStringSplitter sStringColonSplitter = 76 new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); 77 78 protected SwitchPreference mFollowingTypingSwitchPreference; 79 80 // TODO(b/147021230): Move duplicated functions with android/internal/accessibility into util. 81 private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener; 82 private CheckBox mSoftwareTypeCheckBox; 83 private CheckBox mHardwareTypeCheckBox; 84 private CheckBox mTripleTapTypeCheckBox; 85 private DialogCreatable mDialogDelegate; 86 private MagnificationFollowTypingPreferenceController mFollowTypingPreferenceController; 87 88 @Override onCreate(Bundle savedInstanceState)89 public void onCreate(Bundle savedInstanceState) { 90 super.onCreate(savedInstanceState); 91 getActivity().setTitle(R.string.accessibility_screen_magnification_title); 92 } 93 94 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)95 public View onCreateView(LayoutInflater inflater, ViewGroup container, 96 Bundle savedInstanceState) { 97 mPackageName = getString(R.string.accessibility_screen_magnification_title); 98 mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 99 .authority(getPrefContext().getPackageName()) 100 .appendPath(String.valueOf(R.raw.a11y_magnification_banner)) 101 .build(); 102 mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> { 103 removeDialog(DialogEnums.EDIT_SHORTCUT); 104 mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); 105 }; 106 107 final View view = super.onCreateView(inflater, container, savedInstanceState); 108 updateFooterPreference(); 109 return view; 110 } 111 updateFooterPreference()112 private void updateFooterPreference() { 113 final String title = getPrefContext().getString( 114 R.string.accessibility_screen_magnification_about_title); 115 final String learnMoreText = getPrefContext().getString( 116 R.string.accessibility_screen_magnification_footer_learn_more_content_description); 117 mFooterPreferenceController.setIntroductionTitle(title); 118 mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreText); 119 mFooterPreferenceController.displayPreference(getPreferenceScreen()); 120 } 121 122 @Override onResume()123 public void onResume() { 124 super.onResume(); 125 126 final AccessibilityManager am = getPrefContext().getSystemService( 127 AccessibilityManager.class); 128 am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); 129 } 130 131 @Override getPreferenceScreenResId()132 protected int getPreferenceScreenResId() { 133 // TODO(b/171272809): Add back when controllers move to static type 134 return 0; 135 } 136 137 @Override getLogTag()138 protected String getLogTag() { 139 return TAG; 140 } 141 142 @Override onPause()143 public void onPause() { 144 final AccessibilityManager am = getPrefContext().getSystemService( 145 AccessibilityManager.class); 146 am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); 147 148 super.onPause(); 149 } 150 151 @Override onCreateDialog(int dialogId)152 public Dialog onCreateDialog(int dialogId) { 153 if (mDialogDelegate != null) { 154 mDialog = mDialogDelegate.onCreateDialog(dialogId); 155 if (mDialog != null) { 156 return mDialog; 157 } 158 } 159 switch (dialogId) { 160 case DialogEnums.GESTURE_NAVIGATION_TUTORIAL: 161 return AccessibilityGestureNavigationTutorial 162 .showAccessibilityGestureTutorialDialog(getPrefContext()); 163 case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT: 164 final CharSequence dialogTitle = getShortcutTitle(); 165 final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent()) 166 ? DialogType.EDIT_SHORTCUT_MAGNIFICATION_SUW 167 : DialogType.EDIT_SHORTCUT_MAGNIFICATION; 168 mDialog = AccessibilityDialogUtils.showEditShortcutDialog(getPrefContext(), 169 dialogType, dialogTitle, this::callOnAlertDialogCheckboxClicked); 170 setupMagnificationEditShortcutDialog(mDialog); 171 return mDialog; 172 default: 173 return super.onCreateDialog(dialogId); 174 } 175 } 176 177 @Override initSettingsPreference()178 protected void initSettingsPreference() { 179 // If the device doesn't support window magnification feature, it should hide the 180 // settings preference. 181 final boolean supportWindowMagnification = 182 getContext().getResources().getBoolean( 183 com.android.internal.R.bool.config_magnification_area) 184 && getContext().getPackageManager().hasSystemFeature( 185 PackageManager.FEATURE_WINDOW_MAGNIFICATION); 186 if (!supportWindowMagnification) { 187 return; 188 } 189 mSettingsPreference = new Preference(getPrefContext()); 190 mSettingsPreference.setTitle(R.string.accessibility_magnification_mode_title); 191 mSettingsPreference.setKey(MagnificationModePreferenceController.PREF_KEY); 192 mSettingsPreference.setPersistent(false); 193 194 final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY); 195 generalCategory.addPreference(mSettingsPreference); 196 197 final MagnificationModePreferenceController magnificationModePreferenceController = 198 new MagnificationModePreferenceController(getContext(), 199 MagnificationModePreferenceController.PREF_KEY); 200 magnificationModePreferenceController.setDialogHelper(this); 201 getSettingsLifecycle().addObserver(magnificationModePreferenceController); 202 magnificationModePreferenceController.displayPreference(getPreferenceScreen()); 203 204 mFollowingTypingSwitchPreference = 205 new SwitchPreference(getPrefContext()); 206 mFollowingTypingSwitchPreference.setTitle( 207 R.string.accessibility_screen_magnification_follow_typing_title); 208 mFollowingTypingSwitchPreference.setSummary( 209 R.string.accessibility_screen_magnification_follow_typing_summary); 210 mFollowingTypingSwitchPreference.setKey( 211 MagnificationFollowTypingPreferenceController.PREF_KEY); 212 generalCategory.addPreference(mFollowingTypingSwitchPreference); 213 214 mFollowTypingPreferenceController = new MagnificationFollowTypingPreferenceController( 215 getContext(), MagnificationFollowTypingPreferenceController.PREF_KEY); 216 getSettingsLifecycle().addObserver(mFollowTypingPreferenceController); 217 mFollowTypingPreferenceController.displayPreference(getPreferenceScreen()); 218 addPreferenceController(mFollowTypingPreferenceController); 219 220 addAlwaysOnSetting(generalCategory); 221 addJoystickSetting(generalCategory); 222 } 223 224 @Override onProcessArguments(Bundle arguments)225 protected void onProcessArguments(Bundle arguments) { 226 Context context = getContext(); 227 228 // This Fragment may get arguments from MagnificationGesturesPreferenceController or 229 // MagnificationNavbarPreferenceController and it's necessary to check if a key exists 230 // before putting a new value into arguments. 231 232 if (!arguments.containsKey(AccessibilitySettings.EXTRA_PREFERENCE_KEY)) { 233 arguments.putString(AccessibilitySettings.EXTRA_PREFERENCE_KEY, 234 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 235 } 236 237 if (!arguments.containsKey(AccessibilitySettings.EXTRA_INTRO)) { 238 arguments.putCharSequence(AccessibilitySettings.EXTRA_INTRO, 239 context.getString(R.string.accessibility_screen_magnification_intro_text)); 240 } 241 242 if (!arguments.containsKey(AccessibilitySettings.EXTRA_HTML_DESCRIPTION)) { 243 String summary = MessageFormat.format( 244 context.getString(R.string.accessibility_screen_magnification_summary), 245 new Object[]{1, 2, 3, 4, 5}); 246 arguments.putCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, summary); 247 } 248 249 super.onProcessArguments(arguments); 250 } 251 isAlwaysOnSettingEnabled()252 private boolean isAlwaysOnSettingEnabled() { 253 final boolean defaultValue = getContext().getResources().getBoolean( 254 com.android.internal.R.bool.config_magnification_always_on_enabled); 255 256 return DeviceConfig.getBoolean( 257 DeviceConfig.NAMESPACE_WINDOW_MANAGER, 258 "AlwaysOnMagnifier__enable_always_on_magnifier", 259 defaultValue 260 ); 261 } addAlwaysOnSetting(PreferenceCategory generalCategory)262 private void addAlwaysOnSetting(PreferenceCategory generalCategory) { 263 if (!isAlwaysOnSettingEnabled()) { 264 return; 265 } 266 267 var alwaysOnPreference = new SwitchPreference(getPrefContext()); 268 alwaysOnPreference.setTitle( 269 R.string.accessibility_screen_magnification_always_on_title); 270 alwaysOnPreference.setSummary( 271 R.string.accessibility_screen_magnification_always_on_summary); 272 alwaysOnPreference.setKey( 273 MagnificationAlwaysOnPreferenceController.PREF_KEY); 274 generalCategory.addPreference(alwaysOnPreference); 275 276 var alwaysOnPreferenceController = new MagnificationAlwaysOnPreferenceController( 277 getContext(), MagnificationAlwaysOnPreferenceController.PREF_KEY); 278 getSettingsLifecycle().addObserver(alwaysOnPreferenceController); 279 alwaysOnPreferenceController.displayPreference(getPreferenceScreen()); 280 addPreferenceController(alwaysOnPreferenceController); 281 } 282 addJoystickSetting(PreferenceCategory generalCategory)283 private void addJoystickSetting(PreferenceCategory generalCategory) { 284 if (!DeviceConfig.getBoolean( 285 DeviceConfig.NAMESPACE_WINDOW_MANAGER, 286 "MagnificationJoystick__enable_magnification_joystick", 287 false 288 )) { 289 return; 290 } 291 292 SwitchPreference joystickPreference = new SwitchPreference(getPrefContext()); 293 joystickPreference.setTitle( 294 R.string.accessibility_screen_magnification_joystick_title); 295 joystickPreference.setSummary( 296 R.string.accessibility_screen_magnification_joystick_summary); 297 joystickPreference.setKey( 298 MagnificationJoystickPreferenceController.PREF_KEY); 299 generalCategory.addPreference(joystickPreference); 300 301 MagnificationJoystickPreferenceController joystickPreferenceController = 302 new MagnificationJoystickPreferenceController( 303 getContext(), 304 MagnificationJoystickPreferenceController.PREF_KEY 305 ); 306 getSettingsLifecycle().addObserver(joystickPreferenceController); 307 joystickPreferenceController.displayPreference(getPreferenceScreen()); 308 addPreferenceController(joystickPreferenceController); 309 } 310 311 @Override showDialog(int dialogId)312 public void showDialog(int dialogId) { 313 super.showDialog(dialogId); 314 } 315 316 @Override setDialogDelegate(DialogCreatable delegate)317 public void setDialogDelegate(DialogCreatable delegate) { 318 mDialogDelegate = delegate; 319 } 320 321 @Override getShortcutTypeCheckBoxValue()322 protected int getShortcutTypeCheckBoxValue() { 323 if (mSoftwareTypeCheckBox == null || mHardwareTypeCheckBox == null) { 324 return NOT_SET; 325 } 326 327 int value = UserShortcutType.EMPTY; 328 if (mSoftwareTypeCheckBox.isChecked()) { 329 value |= UserShortcutType.SOFTWARE; 330 } 331 if (mHardwareTypeCheckBox.isChecked()) { 332 value |= UserShortcutType.HARDWARE; 333 } 334 if (mTripleTapTypeCheckBox.isChecked()) { 335 value |= UserShortcutType.TRIPLETAP; 336 } 337 return value; 338 } 339 340 @VisibleForTesting setupMagnificationEditShortcutDialog(Dialog dialog)341 void setupMagnificationEditShortcutDialog(Dialog dialog) { 342 final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut); 343 mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox); 344 setDialogTextAreaClickListener(dialogSoftwareView, mSoftwareTypeCheckBox); 345 346 final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut); 347 mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox); 348 setDialogTextAreaClickListener(dialogHardwareView, mHardwareTypeCheckBox); 349 350 final View dialogTripleTapView = dialog.findViewById(R.id.triple_tap_shortcut); 351 mTripleTapTypeCheckBox = dialogTripleTapView.findViewById(R.id.checkbox); 352 setDialogTextAreaClickListener(dialogTripleTapView, mTripleTapTypeCheckBox); 353 354 final View advancedView = dialog.findViewById(R.id.advanced_shortcut); 355 if (mTripleTapTypeCheckBox.isChecked()) { 356 advancedView.setVisibility(View.GONE); 357 dialogTripleTapView.setVisibility(View.VISIBLE); 358 } 359 360 updateMagnificationEditShortcutDialogCheckBox(); 361 } 362 setDialogTextAreaClickListener(View dialogView, CheckBox checkBox)363 private void setDialogTextAreaClickListener(View dialogView, CheckBox checkBox) { 364 final View dialogTextArea = dialogView.findViewById(R.id.container); 365 dialogTextArea.setOnClickListener(v -> checkBox.toggle()); 366 } 367 updateMagnificationEditShortcutDialogCheckBox()368 private void updateMagnificationEditShortcutDialogCheckBox() { 369 // If it is during onConfigChanged process then restore the value, or get the saved value 370 // when shortcutPreference is checked. 371 int value = restoreOnConfigChangedValue(); 372 if (value == NOT_SET) { 373 final int lastNonEmptyUserShortcutType = PreferredShortcuts.retrieveUserShortcutType( 374 getPrefContext(), MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE); 375 value = mShortcutPreference.isChecked() ? lastNonEmptyUserShortcutType 376 : UserShortcutType.EMPTY; 377 } 378 379 mSoftwareTypeCheckBox.setChecked( 380 hasShortcutType(value, UserShortcutType.SOFTWARE)); 381 mHardwareTypeCheckBox.setChecked( 382 hasShortcutType(value, UserShortcutType.HARDWARE)); 383 mTripleTapTypeCheckBox.setChecked( 384 hasShortcutType(value, UserShortcutType.TRIPLETAP)); 385 } 386 restoreOnConfigChangedValue()387 private int restoreOnConfigChangedValue() { 388 final int savedValue = mSavedCheckBoxValue; 389 mSavedCheckBoxValue = NOT_SET; 390 return savedValue; 391 } 392 hasShortcutType(int value, @UserShortcutType int type)393 private boolean hasShortcutType(int value, @UserShortcutType int type) { 394 return (value & type) == type; 395 } 396 getSoftwareShortcutTypeSummary(Context context)397 private static CharSequence getSoftwareShortcutTypeSummary(Context context) { 398 int resId; 399 if (AccessibilityUtil.isFloatingMenuEnabled(context)) { 400 resId = R.string.accessibility_shortcut_edit_summary_software; 401 } else if (AccessibilityUtil.isGestureNavigateEnabled(context)) { 402 resId = R.string.accessibility_shortcut_edit_summary_software_gesture; 403 } else { 404 resId = R.string.accessibility_shortcut_edit_summary_software; 405 } 406 return context.getText(resId); 407 } 408 409 @Override registerKeysToObserverCallback( AccessibilitySettingsContentObserver contentObserver)410 protected void registerKeysToObserverCallback( 411 AccessibilitySettingsContentObserver contentObserver) { 412 super.registerKeysToObserverCallback(contentObserver); 413 414 var keysToObserve = List.of( 415 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, 416 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, 417 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED 418 ); 419 contentObserver.registerKeysToObserverCallback(keysToObserve, 420 key -> updatePreferencesState()); 421 } 422 updatePreferencesState()423 private void updatePreferencesState() { 424 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 425 getPreferenceControllers().forEach(controllers::addAll); 426 controllers.forEach(controller -> controller.updateState( 427 findPreference(controller.getPreferenceKey()))); 428 } 429 430 @Override getShortcutFeatureSettingsKeys()431 protected List<String> getShortcutFeatureSettingsKeys() { 432 final List<String> shortcutKeys = super.getShortcutFeatureSettingsKeys(); 433 shortcutKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 434 return shortcutKeys; 435 } 436 437 @Override getShortcutTypeSummary(Context context)438 protected CharSequence getShortcutTypeSummary(Context context) { 439 if (!mShortcutPreference.isChecked()) { 440 return context.getText(R.string.switch_off_text); 441 } 442 443 final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context, 444 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE); 445 446 final List<CharSequence> list = new ArrayList<>(); 447 if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) { 448 list.add(getSoftwareShortcutTypeSummary(context)); 449 } 450 if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) { 451 final CharSequence hardwareTitle = context.getText( 452 R.string.accessibility_shortcut_hardware_keyword); 453 list.add(hardwareTitle); 454 } 455 if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) { 456 final CharSequence tripleTapTitle = context.getText( 457 R.string.accessibility_shortcut_triple_tap_keyword); 458 list.add(tripleTapTitle); 459 } 460 461 // Show software shortcut if first time to use. 462 if (list.isEmpty()) { 463 list.add(getSoftwareShortcutTypeSummary(context)); 464 } 465 466 return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */ 467 null, LocaleUtils.getConcatenatedString(list)); 468 } 469 470 @Override callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which)471 protected void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) { 472 final int value = getShortcutTypeCheckBoxValue(); 473 474 saveNonEmptyUserShortcutType(value); 475 optInAllMagnificationValuesToSettings(getPrefContext(), value); 476 optOutAllMagnificationValuesFromSettings(getPrefContext(), ~value); 477 mShortcutPreference.setChecked(value != UserShortcutType.EMPTY); 478 mShortcutPreference.setSummary( 479 getShortcutTypeSummary(getPrefContext())); 480 481 if (mHardwareTypeCheckBox.isChecked()) { 482 AccessibilityUtil.skipVolumeShortcutDialogTimeoutRestriction(getPrefContext()); 483 } 484 } 485 486 @Override getHelpResource()487 public int getHelpResource() { 488 return R.string.help_url_magnification; 489 } 490 491 @Override getMetricsCategory()492 public int getMetricsCategory() { 493 // TODO: Distinguish between magnification modes 494 return SettingsEnums.ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION; 495 } 496 497 @Override getDialogMetricsCategory(int dialogId)498 public int getDialogMetricsCategory(int dialogId) { 499 if (mDialogDelegate != null) { 500 final int category = mDialogDelegate.getDialogMetricsCategory(dialogId); 501 if (category != 0) { 502 return category; 503 } 504 } 505 506 switch (dialogId) { 507 case DialogEnums.GESTURE_NAVIGATION_TUTORIAL: 508 return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION; 509 case DialogEnums.ACCESSIBILITY_BUTTON_TUTORIAL: 510 return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_ACCESSIBILITY_BUTTON; 511 case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT: 512 return SettingsEnums.DIALOG_MAGNIFICATION_EDIT_SHORTCUT; 513 default: 514 return super.getDialogMetricsCategory(dialogId); 515 } 516 } 517 518 @Override getUserShortcutTypes()519 int getUserShortcutTypes() { 520 return getUserShortcutTypeFromSettings(getPrefContext()); 521 } 522 523 @Override getTileComponentName()524 ComponentName getTileComponentName() { 525 return null; 526 } 527 528 @Override getTileTooltipContent(@uickSettingsTooltipType int type)529 CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) { 530 return null; 531 } 532 533 @Override onPreferenceToggled(String preferenceKey, boolean enabled)534 protected void onPreferenceToggled(String preferenceKey, boolean enabled) { 535 if (enabled && TextUtils.equals( 536 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 537 preferenceKey)) { 538 showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL); 539 } 540 MagnificationPreferenceFragment.setChecked(getContentResolver(), preferenceKey, enabled); 541 } 542 543 @Override onInstallSwitchPreferenceToggleSwitch()544 protected void onInstallSwitchPreferenceToggleSwitch() { 545 mToggleServiceSwitchPreference.setVisible(false); 546 } 547 548 @Override onToggleClicked(ShortcutPreference preference)549 public void onToggleClicked(ShortcutPreference preference) { 550 final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(), 551 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE); 552 if (preference.isChecked()) { 553 optInAllMagnificationValuesToSettings(getPrefContext(), shortcutTypes); 554 showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL); 555 } else { 556 optOutAllMagnificationValuesFromSettings(getPrefContext(), shortcutTypes); 557 } 558 mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); 559 } 560 561 @Override onSettingsClicked(ShortcutPreference preference)562 public void onSettingsClicked(ShortcutPreference preference) { 563 showDialog(DialogEnums.MAGNIFICATION_EDIT_SHORTCUT); 564 } 565 566 @Override updateShortcutPreferenceData()567 protected void updateShortcutPreferenceData() { 568 final int shortcutTypes = getUserShortcutTypeFromSettings(getPrefContext()); 569 if (shortcutTypes != UserShortcutType.EMPTY) { 570 final PreferredShortcut shortcut = new PreferredShortcut( 571 MAGNIFICATION_CONTROLLER_NAME, shortcutTypes); 572 PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut); 573 } 574 } 575 576 @Override initShortcutPreference()577 protected void initShortcutPreference() { 578 mShortcutPreference = new ShortcutPreference(getPrefContext(), null); 579 mShortcutPreference.setPersistent(false); 580 mShortcutPreference.setKey(getShortcutPreferenceKey()); 581 mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); 582 mShortcutPreference.setOnClickCallback(this); 583 mShortcutPreference.setTitle(getShortcutTitle()); 584 585 final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY); 586 generalCategory.addPreference(mShortcutPreference); 587 } 588 589 @Override getShortcutTitle()590 protected CharSequence getShortcutTitle() { 591 return getText(R.string.accessibility_screen_magnification_shortcut_title); 592 } 593 594 @Override updateShortcutPreference()595 protected void updateShortcutPreference() { 596 final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(), 597 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE); 598 mShortcutPreference.setChecked( 599 hasMagnificationValuesInSettings(getPrefContext(), shortcutTypes)); 600 mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); 601 } 602 603 @VisibleForTesting saveNonEmptyUserShortcutType(int type)604 void saveNonEmptyUserShortcutType(int type) { 605 if (type == UserShortcutType.EMPTY) { 606 return; 607 } 608 609 final PreferredShortcut shortcut = new PreferredShortcut( 610 MAGNIFICATION_CONTROLLER_NAME, type); 611 PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut); 612 } 613 614 @VisibleForTesting optInAllMagnificationValuesToSettings(Context context, int shortcutTypes)615 static void optInAllMagnificationValuesToSettings(Context context, int shortcutTypes) { 616 if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { 617 optInMagnificationValueToSettings(context, UserShortcutType.SOFTWARE); 618 } 619 if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { 620 optInMagnificationValueToSettings(context, UserShortcutType.HARDWARE); 621 } 622 if (((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP)) { 623 optInMagnificationValueToSettings(context, UserShortcutType.TRIPLETAP); 624 } 625 } 626 optInMagnificationValueToSettings(Context context, @UserShortcutType int shortcutType)627 private static void optInMagnificationValueToSettings(Context context, 628 @UserShortcutType int shortcutType) { 629 if (shortcutType == UserShortcutType.TRIPLETAP) { 630 Settings.Secure.putInt(context.getContentResolver(), 631 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON); 632 return; 633 } 634 635 if (hasMagnificationValueInSettings(context, shortcutType)) { 636 return; 637 } 638 639 final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType); 640 final String targetString = Settings.Secure.getString(context.getContentResolver(), 641 targetKey); 642 final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR)); 643 644 if (!TextUtils.isEmpty(targetString)) { 645 joiner.add(targetString); 646 } 647 joiner.add(MAGNIFICATION_CONTROLLER_NAME); 648 649 Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString()); 650 } 651 652 @VisibleForTesting optOutAllMagnificationValuesFromSettings(Context context, int shortcutTypes)653 static void optOutAllMagnificationValuesFromSettings(Context context, 654 int shortcutTypes) { 655 if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { 656 optOutMagnificationValueFromSettings(context, UserShortcutType.SOFTWARE); 657 } 658 if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { 659 optOutMagnificationValueFromSettings(context, UserShortcutType.HARDWARE); 660 } 661 if (((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP)) { 662 optOutMagnificationValueFromSettings(context, UserShortcutType.TRIPLETAP); 663 } 664 } 665 optOutMagnificationValueFromSettings(Context context, @UserShortcutType int shortcutType)666 private static void optOutMagnificationValueFromSettings(Context context, 667 @UserShortcutType int shortcutType) { 668 if (shortcutType == UserShortcutType.TRIPLETAP) { 669 Settings.Secure.putInt(context.getContentResolver(), 670 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF); 671 return; 672 } 673 674 final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType); 675 final String targetString = Settings.Secure.getString(context.getContentResolver(), 676 targetKey); 677 678 if (TextUtils.isEmpty(targetString)) { 679 return; 680 } 681 682 final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR)); 683 684 sStringColonSplitter.setString(targetString); 685 while (sStringColonSplitter.hasNext()) { 686 final String name = sStringColonSplitter.next(); 687 if (TextUtils.isEmpty(name) || MAGNIFICATION_CONTROLLER_NAME.equals(name)) { 688 continue; 689 } 690 joiner.add(name); 691 } 692 693 Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString()); 694 } 695 696 @VisibleForTesting hasMagnificationValuesInSettings(Context context, int shortcutTypes)697 static boolean hasMagnificationValuesInSettings(Context context, int shortcutTypes) { 698 boolean exist = false; 699 700 if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { 701 exist = hasMagnificationValueInSettings(context, UserShortcutType.SOFTWARE); 702 } 703 if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { 704 exist |= hasMagnificationValueInSettings(context, UserShortcutType.HARDWARE); 705 } 706 if (((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP)) { 707 exist |= hasMagnificationValueInSettings(context, UserShortcutType.TRIPLETAP); 708 } 709 return exist; 710 } 711 hasMagnificationValueInSettings(Context context, @UserShortcutType int shortcutType)712 private static boolean hasMagnificationValueInSettings(Context context, 713 @UserShortcutType int shortcutType) { 714 if (shortcutType == UserShortcutType.TRIPLETAP) { 715 return Settings.Secure.getInt(context.getContentResolver(), 716 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON; 717 } 718 719 final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType); 720 final String targetString = Settings.Secure.getString(context.getContentResolver(), 721 targetKey); 722 723 if (TextUtils.isEmpty(targetString)) { 724 return false; 725 } 726 727 sStringColonSplitter.setString(targetString); 728 while (sStringColonSplitter.hasNext()) { 729 final String name = sStringColonSplitter.next(); 730 if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) { 731 return true; 732 } 733 } 734 return false; 735 } 736 getUserShortcutTypeFromSettings(Context context)737 private static int getUserShortcutTypeFromSettings(Context context) { 738 int shortcutTypes = UserShortcutType.EMPTY; 739 if (hasMagnificationValuesInSettings(context, UserShortcutType.SOFTWARE)) { 740 shortcutTypes |= UserShortcutType.SOFTWARE; 741 } 742 if (hasMagnificationValuesInSettings(context, UserShortcutType.HARDWARE)) { 743 shortcutTypes |= UserShortcutType.HARDWARE; 744 } 745 if (hasMagnificationValuesInSettings(context, UserShortcutType.TRIPLETAP)) { 746 shortcutTypes |= UserShortcutType.TRIPLETAP; 747 } 748 return shortcutTypes; 749 } 750 751 /** 752 * Gets the service summary of magnification. 753 * 754 * @param context The current context. 755 */ getServiceSummary(Context context)756 public static CharSequence getServiceSummary(Context context) { 757 // Get the user shortcut type from settings provider. 758 final int uerShortcutType = getUserShortcutTypeFromSettings(context); 759 return (uerShortcutType != AccessibilityUtil.UserShortcutType.EMPTY) 760 ? context.getText(R.string.accessibility_summary_shortcut_enabled) 761 : context.getText(R.string.accessibility_summary_shortcut_disabled); 762 } 763 } 764