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