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.ContentResolver;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.icu.text.CaseMap;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.provider.Settings;
33 import android.text.TextUtils;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.view.accessibility.AccessibilityManager;
38 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
39 import android.widget.CheckBox;
40 
41 import androidx.preference.Preference;
42 import androidx.preference.PreferenceCategory;
43 
44 import com.android.internal.annotations.VisibleForTesting;
45 import com.android.settings.DialogCreatable;
46 import com.android.settings.R;
47 import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType;
48 import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
49 import com.android.settings.utils.LocaleUtils;
50 
51 import com.google.android.setupcompat.util.WizardManagerHelper;
52 
53 import java.util.ArrayList;
54 import java.util.List;
55 import java.util.Locale;
56 import java.util.StringJoiner;
57 
58 /**
59  * Fragment that shows the actual UI for providing basic magnification accessibility service setup
60  * and does not have toggle bar to turn on service to use.
61  */
62 public class ToggleScreenMagnificationPreferenceFragment extends
63         ToggleFeaturePreferenceFragment implements
64         MagnificationModePreferenceController.DialogHelper {
65     // TODO(b/147021230): Move duplicated functions with android/internal/accessibility into util.
66     private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
67 
68     private CheckBox mSoftwareTypeCheckBox;
69     private CheckBox mHardwareTypeCheckBox;
70     private CheckBox mTripleTapTypeCheckBox;
71 
72     private static final char COMPONENT_NAME_SEPARATOR = ':';
73     private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
74             new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
75 
76     private MagnificationModePreferenceController mModePreferenceController;
77     private DialogCreatable mDialogDelegate;
78 
79     @Override
onCreate(Bundle savedInstanceState)80     public void onCreate(Bundle savedInstanceState) {
81         super.onCreate(savedInstanceState);
82         getActivity().setTitle(R.string.accessibility_screen_magnification_title);
83     }
84 
85     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)86     public View onCreateView(LayoutInflater inflater, ViewGroup container,
87             Bundle savedInstanceState) {
88         mPackageName = getString(R.string.accessibility_screen_magnification_title);
89         mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
90                 .authority(getPrefContext().getPackageName())
91                 .appendPath(String.valueOf(R.raw.accessibility_magnification_banner))
92                 .build();
93         mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> {
94             removeDialog(DialogEnums.EDIT_SHORTCUT);
95             mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
96         };
97 
98         final View view = super.onCreateView(inflater, container, savedInstanceState);
99         updateFooterPreference();
100         return view;
101     }
102 
updateFooterPreference()103     private void updateFooterPreference() {
104         final String title = getPrefContext().getString(
105                 R.string.accessibility_screen_magnification_about_title);
106         final String learnMoreContentDescription = getPrefContext().getString(
107                 R.string.accessibility_screen_magnification_footer_learn_more_content_description);
108         mFooterPreferenceController.setIntroductionTitle(title);
109         mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
110         mFooterPreferenceController.displayPreference(getPreferenceScreen());
111     }
112 
113     @Override
onResume()114     public void onResume() {
115         super.onResume();
116 
117         final AccessibilityManager am = getPrefContext().getSystemService(
118                 AccessibilityManager.class);
119         am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
120     }
121 
122     @Override
onPause()123     public void onPause() {
124         final AccessibilityManager am = getPrefContext().getSystemService(
125                 AccessibilityManager.class);
126         am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
127 
128         super.onPause();
129     }
130 
131     @Override
onCreateDialog(int dialogId)132     public Dialog onCreateDialog(int dialogId) {
133         if (mDialogDelegate != null) {
134             mDialog = mDialogDelegate.onCreateDialog(dialogId);
135             if (mDialog != null) {
136                 return mDialog;
137             }
138         }
139         switch (dialogId) {
140             case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
141                 return AccessibilityGestureNavigationTutorial
142                         .showAccessibilityGestureTutorialDialog(getPrefContext());
143             case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
144                 final CharSequence dialogTitle = getPrefContext().getString(
145                         R.string.accessibility_shortcut_title, mPackageName);
146                 final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
147                         ? DialogType.EDIT_SHORTCUT_MAGNIFICATION_SUW
148                         : DialogType.EDIT_SHORTCUT_MAGNIFICATION;
149                 mDialog = AccessibilityDialogUtils.showEditShortcutDialog(getPrefContext(),
150                         dialogType, dialogTitle, this::callOnAlertDialogCheckboxClicked);
151                 setupMagnificationEditShortcutDialog(mDialog);
152                 return mDialog;
153             default:
154                 return super.onCreateDialog(dialogId);
155         }
156     }
157 
158     @Override
initSettingsPreference()159     protected void initSettingsPreference() {
160         // If the device doesn't support magnification area, it should hide the settings preference.
161         if (!getContext().getResources().getBoolean(
162                 com.android.internal.R.bool.config_magnification_area)) {
163             return;
164         }
165         mSettingsPreference = new Preference(getPrefContext());
166         mSettingsPreference.setTitle(R.string.accessibility_magnification_mode_title);
167         mSettingsPreference.setKey(MagnificationModePreferenceController.PREF_KEY);
168         mSettingsPreference.setPersistent(false);
169 
170         final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
171         generalCategory.addPreference(mSettingsPreference);
172 
173         mModePreferenceController = new MagnificationModePreferenceController(getContext(),
174                 MagnificationModePreferenceController.PREF_KEY);
175         mModePreferenceController.setDialogHelper(this);
176         getSettingsLifecycle().addObserver(mModePreferenceController);
177         mModePreferenceController.displayPreference(getPreferenceScreen());
178     }
179 
180     @Override
showDialog(int dialogId)181     public void showDialog(int dialogId) {
182         super.showDialog(dialogId);
183     }
184 
185     @Override
setDialogDelegate(DialogCreatable delegate)186     public void setDialogDelegate(DialogCreatable delegate) {
187         mDialogDelegate = delegate;
188     }
189 
190     @Override
getShortcutTypeCheckBoxValue()191     protected int getShortcutTypeCheckBoxValue() {
192         if (mSoftwareTypeCheckBox == null || mHardwareTypeCheckBox == null) {
193             return NOT_SET;
194         }
195 
196         int value = UserShortcutType.EMPTY;
197         if (mSoftwareTypeCheckBox.isChecked()) {
198             value |= UserShortcutType.SOFTWARE;
199         }
200         if (mHardwareTypeCheckBox.isChecked()) {
201             value |= UserShortcutType.HARDWARE;
202         }
203         if (mTripleTapTypeCheckBox.isChecked()) {
204             value |= UserShortcutType.TRIPLETAP;
205         }
206         return value;
207     }
208 
209     @VisibleForTesting
setupMagnificationEditShortcutDialog(Dialog dialog)210     void setupMagnificationEditShortcutDialog(Dialog dialog) {
211         final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut);
212         mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox);
213         setDialogTextAreaClickListener(dialogSoftwareView, mSoftwareTypeCheckBox);
214 
215         final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut);
216         mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox);
217         setDialogTextAreaClickListener(dialogHardwareView, mHardwareTypeCheckBox);
218 
219         final View dialogTripleTapView = dialog.findViewById(R.id.triple_tap_shortcut);
220         mTripleTapTypeCheckBox = dialogTripleTapView.findViewById(R.id.checkbox);
221         setDialogTextAreaClickListener(dialogTripleTapView, mTripleTapTypeCheckBox);
222 
223         final View advancedView = dialog.findViewById(R.id.advanced_shortcut);
224         if (mTripleTapTypeCheckBox.isChecked()) {
225             advancedView.setVisibility(View.GONE);
226             dialogTripleTapView.setVisibility(View.VISIBLE);
227         }
228 
229         updateMagnificationEditShortcutDialogCheckBox();
230     }
231 
setDialogTextAreaClickListener(View dialogView, CheckBox checkBox)232     private void setDialogTextAreaClickListener(View dialogView, CheckBox checkBox) {
233         final View dialogTextArea = dialogView.findViewById(R.id.container);
234         dialogTextArea.setOnClickListener(v -> checkBox.toggle());
235     }
236 
updateMagnificationEditShortcutDialogCheckBox()237     private void updateMagnificationEditShortcutDialogCheckBox() {
238         // If it is during onConfigChanged process then restore the value, or get the saved value
239         // when shortcutPreference is checked.
240         int value = restoreOnConfigChangedValue();
241         if (value == NOT_SET) {
242             final int lastNonEmptyUserShortcutType = PreferredShortcuts.retrieveUserShortcutType(
243                     getPrefContext(), MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
244             value = mShortcutPreference.isChecked() ? lastNonEmptyUserShortcutType
245                     : UserShortcutType.EMPTY;
246         }
247 
248         mSoftwareTypeCheckBox.setChecked(
249                 hasShortcutType(value, UserShortcutType.SOFTWARE));
250         mHardwareTypeCheckBox.setChecked(
251                 hasShortcutType(value, UserShortcutType.HARDWARE));
252         mTripleTapTypeCheckBox.setChecked(
253                 hasShortcutType(value, UserShortcutType.TRIPLETAP));
254     }
255 
restoreOnConfigChangedValue()256     private int restoreOnConfigChangedValue() {
257         final int savedValue = mSavedCheckBoxValue;
258         mSavedCheckBoxValue = NOT_SET;
259         return savedValue;
260     }
261 
hasShortcutType(int value, @UserShortcutType int type)262     private boolean hasShortcutType(int value, @UserShortcutType int type) {
263         return (value & type) == type;
264     }
265 
getSoftwareShortcutTypeSummary(Context context)266     private static CharSequence getSoftwareShortcutTypeSummary(Context context) {
267         int resId;
268         if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
269             resId = R.string.accessibility_shortcut_edit_summary_software;
270         } else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
271             resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
272         } else {
273             resId = R.string.accessibility_shortcut_edit_summary_software;
274         }
275         return context.getText(resId);
276     }
277 
278     @Override
getFeatureSettingsKeys()279     protected List<String> getFeatureSettingsKeys() {
280         final List<String> shortcutKeys = super.getFeatureSettingsKeys();
281         shortcutKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
282         return shortcutKeys;
283     }
284 
285     @Override
getShortcutTypeSummary(Context context)286     protected CharSequence getShortcutTypeSummary(Context context) {
287         if (!mShortcutPreference.isChecked()) {
288             return context.getText(R.string.switch_off_text);
289         }
290 
291         final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
292                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
293 
294         final List<CharSequence> list = new ArrayList<>();
295         if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
296             list.add(getSoftwareShortcutTypeSummary(context));
297         }
298         if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
299             final CharSequence hardwareTitle = context.getText(
300                     R.string.accessibility_shortcut_hardware_keyword);
301             list.add(hardwareTitle);
302         }
303         if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) {
304             final CharSequence tripleTapTitle = context.getText(
305                     R.string.accessibility_shortcut_triple_tap_keyword);
306             list.add(tripleTapTitle);
307         }
308 
309         // Show software shortcut if first time to use.
310         if (list.isEmpty()) {
311             list.add(getSoftwareShortcutTypeSummary(context));
312         }
313 
314         return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
315                 null, LocaleUtils.getConcatenatedString(list));
316     }
317 
318     @Override
callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which)319     protected void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) {
320         final int value = getShortcutTypeCheckBoxValue();
321 
322         saveNonEmptyUserShortcutType(value);
323         optInAllMagnificationValuesToSettings(getPrefContext(), value);
324         optOutAllMagnificationValuesFromSettings(getPrefContext(), ~value);
325         mShortcutPreference.setChecked(value != UserShortcutType.EMPTY);
326         mShortcutPreference.setSummary(
327                 getShortcutTypeSummary(getPrefContext()));
328     }
329 
330     @Override
getHelpResource()331     public int getHelpResource() {
332         return R.string.help_url_magnification;
333     }
334 
335     @Override
getMetricsCategory()336     public int getMetricsCategory() {
337         // TODO: Distinguish between magnification modes
338         return SettingsEnums.ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION;
339     }
340 
341     @Override
getDialogMetricsCategory(int dialogId)342     public int getDialogMetricsCategory(int dialogId) {
343         if (mDialogDelegate != null) {
344             final int category = mDialogDelegate.getDialogMetricsCategory(dialogId);
345             if (category != 0) {
346                 return category;
347             }
348         }
349 
350         switch (dialogId) {
351             case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
352                 return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION;
353             case DialogEnums.ACCESSIBILITY_BUTTON_TUTORIAL:
354                 return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_ACCESSIBILITY_BUTTON;
355             case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
356                 return SettingsEnums.DIALOG_MAGNIFICATION_EDIT_SHORTCUT;
357             default:
358                 return super.getDialogMetricsCategory(dialogId);
359         }
360     }
361 
362     @Override
getUserShortcutTypes()363     int getUserShortcutTypes() {
364         return getUserShortcutTypeFromSettings(getPrefContext());
365     }
366 
367     @Override
onPreferenceToggled(String preferenceKey, boolean enabled)368     protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
369         if (enabled && TextUtils.equals(
370                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
371                 preferenceKey)) {
372             showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
373         }
374         MagnificationPreferenceFragment.setChecked(getContentResolver(), preferenceKey, enabled);
375     }
376 
377     @Override
onInstallSwitchPreferenceToggleSwitch()378     protected void onInstallSwitchPreferenceToggleSwitch() {
379         mToggleServiceSwitchPreference.setVisible(false);
380     }
381 
382     @Override
onToggleClicked(ShortcutPreference preference)383     public void onToggleClicked(ShortcutPreference preference) {
384         final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
385                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
386         if (preference.isChecked()) {
387             optInAllMagnificationValuesToSettings(getPrefContext(), shortcutTypes);
388             showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
389         } else {
390             optOutAllMagnificationValuesFromSettings(getPrefContext(), shortcutTypes);
391         }
392         mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
393     }
394 
395     @Override
onSettingsClicked(ShortcutPreference preference)396     public void onSettingsClicked(ShortcutPreference preference) {
397         showDialog(DialogEnums.MAGNIFICATION_EDIT_SHORTCUT);
398     }
399 
400     @Override
updateShortcutPreferenceData()401     protected void updateShortcutPreferenceData() {
402         final int shortcutTypes = getUserShortcutTypeFromSettings(getPrefContext());
403         if (shortcutTypes != UserShortcutType.EMPTY) {
404             final PreferredShortcut shortcut = new PreferredShortcut(
405                     MAGNIFICATION_CONTROLLER_NAME, shortcutTypes);
406             PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
407         }
408     }
409 
410     @Override
initShortcutPreference()411     protected void initShortcutPreference() {
412         mShortcutPreference = new ShortcutPreference(getPrefContext(), null);
413         mShortcutPreference.setPersistent(false);
414         mShortcutPreference.setKey(getShortcutPreferenceKey());
415         mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
416         mShortcutPreference.setOnClickCallback(this);
417 
418         final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
419         mShortcutPreference.setTitle(title);
420 
421         final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
422         generalCategory.addPreference(mShortcutPreference);
423     }
424 
425     @Override
updateShortcutTitle(ShortcutPreference shortcutPreference)426     protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
427         shortcutPreference.setTitle(R.string.accessibility_screen_magnification_shortcut_title);
428     }
429 
430     @Override
updateShortcutPreference()431     protected void updateShortcutPreference() {
432         final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
433                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
434         mShortcutPreference.setChecked(
435                 hasMagnificationValuesInSettings(getPrefContext(), shortcutTypes));
436         mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
437     }
438 
439     @VisibleForTesting
saveNonEmptyUserShortcutType(int type)440     void saveNonEmptyUserShortcutType(int type) {
441         if (type == UserShortcutType.EMPTY) {
442             return;
443         }
444 
445         final PreferredShortcut shortcut = new PreferredShortcut(
446                 MAGNIFICATION_CONTROLLER_NAME, type);
447         PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
448     }
449 
450     @VisibleForTesting
optInAllMagnificationValuesToSettings(Context context, int shortcutTypes)451     static void optInAllMagnificationValuesToSettings(Context context, int shortcutTypes) {
452         if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
453             optInMagnificationValueToSettings(context, UserShortcutType.SOFTWARE);
454         }
455         if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {
456             optInMagnificationValueToSettings(context, UserShortcutType.HARDWARE);
457         }
458         if (((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP)) {
459             optInMagnificationValueToSettings(context, UserShortcutType.TRIPLETAP);
460         }
461     }
462 
optInMagnificationValueToSettings(Context context, @UserShortcutType int shortcutType)463     private static void optInMagnificationValueToSettings(Context context,
464             @UserShortcutType int shortcutType) {
465         if (shortcutType == UserShortcutType.TRIPLETAP) {
466             Settings.Secure.putInt(context.getContentResolver(),
467                     Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON);
468             return;
469         }
470 
471         if (hasMagnificationValueInSettings(context, shortcutType)) {
472             return;
473         }
474 
475         final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType);
476         final String targetString = Settings.Secure.getString(context.getContentResolver(),
477                 targetKey);
478         final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
479 
480         if (!TextUtils.isEmpty(targetString)) {
481             joiner.add(targetString);
482         }
483         joiner.add(MAGNIFICATION_CONTROLLER_NAME);
484 
485         Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
486     }
487 
488     @VisibleForTesting
optOutAllMagnificationValuesFromSettings(Context context, int shortcutTypes)489     static void optOutAllMagnificationValuesFromSettings(Context context,
490             int shortcutTypes) {
491         if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
492             optOutMagnificationValueFromSettings(context, UserShortcutType.SOFTWARE);
493         }
494         if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {
495             optOutMagnificationValueFromSettings(context, UserShortcutType.HARDWARE);
496         }
497         if (((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP)) {
498             optOutMagnificationValueFromSettings(context, UserShortcutType.TRIPLETAP);
499         }
500     }
501 
optOutMagnificationValueFromSettings(Context context, @UserShortcutType int shortcutType)502     private static void optOutMagnificationValueFromSettings(Context context,
503             @UserShortcutType int shortcutType) {
504         if (shortcutType == UserShortcutType.TRIPLETAP) {
505             Settings.Secure.putInt(context.getContentResolver(),
506                     Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF);
507             return;
508         }
509 
510         final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType);
511         final String targetString = Settings.Secure.getString(context.getContentResolver(),
512                 targetKey);
513 
514         if (TextUtils.isEmpty(targetString)) {
515             return;
516         }
517 
518         final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
519 
520         sStringColonSplitter.setString(targetString);
521         while (sStringColonSplitter.hasNext()) {
522             final String name = sStringColonSplitter.next();
523             if (TextUtils.isEmpty(name) || MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
524                 continue;
525             }
526             joiner.add(name);
527         }
528 
529         Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
530     }
531 
532     @VisibleForTesting
hasMagnificationValuesInSettings(Context context, int shortcutTypes)533     static boolean hasMagnificationValuesInSettings(Context context, int shortcutTypes) {
534         boolean exist = false;
535 
536         if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) {
537             exist = hasMagnificationValueInSettings(context, UserShortcutType.SOFTWARE);
538         }
539         if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) {
540             exist |= hasMagnificationValueInSettings(context, UserShortcutType.HARDWARE);
541         }
542         if (((shortcutTypes & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP)) {
543             exist |= hasMagnificationValueInSettings(context, UserShortcutType.TRIPLETAP);
544         }
545         return exist;
546     }
547 
hasMagnificationValueInSettings(Context context, @UserShortcutType int shortcutType)548     private static boolean hasMagnificationValueInSettings(Context context,
549             @UserShortcutType int shortcutType) {
550         if (shortcutType == UserShortcutType.TRIPLETAP) {
551             return Settings.Secure.getInt(context.getContentResolver(),
552                     Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
553         }
554 
555         final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType);
556         final String targetString = Settings.Secure.getString(context.getContentResolver(),
557                 targetKey);
558 
559         if (TextUtils.isEmpty(targetString)) {
560             return false;
561         }
562 
563         sStringColonSplitter.setString(targetString);
564         while (sStringColonSplitter.hasNext()) {
565             final String name = sStringColonSplitter.next();
566             if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
567                 return true;
568             }
569         }
570         return false;
571     }
572 
isWindowMagnification(Context context)573     private boolean isWindowMagnification(Context context) {
574         final int mode = Settings.Secure.getIntForUser(
575                 context.getContentResolver(),
576                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
577                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
578                 context.getContentResolver().getUserId());
579         return mode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
580     }
581 
getUserShortcutTypeFromSettings(Context context)582     private static int getUserShortcutTypeFromSettings(Context context) {
583         int shortcutTypes = UserShortcutType.EMPTY;
584         if (hasMagnificationValuesInSettings(context, UserShortcutType.SOFTWARE)) {
585             shortcutTypes |= UserShortcutType.SOFTWARE;
586         }
587         if (hasMagnificationValuesInSettings(context, UserShortcutType.HARDWARE)) {
588             shortcutTypes |= UserShortcutType.HARDWARE;
589         }
590         if (hasMagnificationValuesInSettings(context, UserShortcutType.TRIPLETAP)) {
591             shortcutTypes |= UserShortcutType.TRIPLETAP;
592         }
593         return shortcutTypes;
594     }
595 
596     /**
597      * Gets the service summary of magnification.
598      *
599      * @param context The current context.
600      */
getServiceSummary(Context context)601     public static CharSequence getServiceSummary(Context context) {
602         // Get the user shortcut type from settings provider.
603         final int uerShortcutType = getUserShortcutTypeFromSettings(context);
604         return (uerShortcutType != AccessibilityUtil.UserShortcutType.EMPTY)
605                 ? context.getText(R.string.accessibility_summary_shortcut_enabled)
606                 : context.getText(R.string.accessibility_summary_shortcut_disabled);
607     }
608 }
609