• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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