• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.internal.accessibility.util;
18 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
19 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
20 
21 import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
22 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
23 
24 import android.annotation.NonNull;
25 import android.content.Context;
26 import android.provider.Settings;
27 import android.text.TextUtils;
28 import android.view.accessibility.AccessibilityManager;
29 import android.view.accessibility.AccessibilityManager.ShortcutType;
30 
31 import java.util.List;
32 import java.util.StringJoiner;
33 
34 /**
35  * Collection of utilities for accessibility shortcut.
36  */
37 public final class ShortcutUtils {
ShortcutUtils()38     private ShortcutUtils() {}
39 
40     private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
41             new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
42 
43     /**
44      * Opts in component id into colon-separated {@link UserShortcutType}
45      * key's string from Settings.
46      *
47      * @param context The current context.
48      * @param shortcutType The preferred shortcut type user selected.
49      * @param componentId The component id that need to be opted in Settings.
50      */
optInValueToSettings(Context context, @UserShortcutType int shortcutType, @NonNull String componentId)51     public static void optInValueToSettings(Context context, @UserShortcutType int shortcutType,
52             @NonNull String componentId) {
53         final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
54         final String targetKey = convertToKey(shortcutType);
55         final String targetString = Settings.Secure.getString(context.getContentResolver(),
56                 targetKey);
57 
58         if (isComponentIdExistingInSettings(context, shortcutType, componentId)) {
59             return;
60         }
61 
62         if (!TextUtils.isEmpty(targetString)) {
63             joiner.add(targetString);
64         }
65         joiner.add(componentId);
66 
67         Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
68     }
69 
70     /**
71      * Opts out of component id into colon-separated {@link UserShortcutType} key's string from
72      * Settings.
73      *
74      * @param context The current context.
75      * @param shortcutType The preferred shortcut type user selected.
76      * @param componentId The component id that need to be opted out of Settings.
77      */
optOutValueFromSettings( Context context, @UserShortcutType int shortcutType, @NonNull String componentId)78     public static void optOutValueFromSettings(
79             Context context, @UserShortcutType int shortcutType, @NonNull String componentId) {
80         final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
81         final String targetsKey = convertToKey(shortcutType);
82         final String targetsValue = Settings.Secure.getString(context.getContentResolver(),
83                 targetsKey);
84 
85         if (TextUtils.isEmpty(targetsValue)) {
86             return;
87         }
88 
89         sStringColonSplitter.setString(targetsValue);
90         while (sStringColonSplitter.hasNext()) {
91             final String id = sStringColonSplitter.next();
92             if (TextUtils.isEmpty(id) || componentId.equals(id)) {
93                 continue;
94             }
95             joiner.add(id);
96         }
97 
98         Settings.Secure.putString(context.getContentResolver(), targetsKey, joiner.toString());
99     }
100 
101     /**
102      * Returns if component id existed in Settings.
103      *
104      * @param context The current context.
105      * @param shortcutType The preferred shortcut type user selected.
106      * @param componentId The component id that need to be checked existed in Settings.
107      * @return {@code true} if component id existed in Settings.
108      */
isComponentIdExistingInSettings(Context context, @UserShortcutType int shortcutType, @NonNull String componentId)109     public static boolean isComponentIdExistingInSettings(Context context,
110             @UserShortcutType int shortcutType, @NonNull String componentId) {
111         final String targetKey = convertToKey(shortcutType);
112         final String targetString = Settings.Secure.getString(context.getContentResolver(),
113                 targetKey);
114 
115         if (TextUtils.isEmpty(targetString)) {
116             return false;
117         }
118 
119         sStringColonSplitter.setString(targetString);
120         while (sStringColonSplitter.hasNext()) {
121             final String id = sStringColonSplitter.next();
122             if (componentId.equals(id)) {
123                 return true;
124             }
125         }
126 
127         return false;
128     }
129 
130     /**
131      * Returns if a {@code shortcutType} shortcut contains {@code componentId}.
132      *
133      * @param context The current context.
134      * @param shortcutType The preferred shortcut type user selected.
135      * @param componentId The component id that need to be checked.
136      * @return {@code true} if a component id is contained.
137      */
isShortcutContained(Context context, @ShortcutType int shortcutType, @NonNull String componentId)138     public static boolean isShortcutContained(Context context, @ShortcutType int shortcutType,
139             @NonNull String componentId) {
140         final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
141                 Context.ACCESSIBILITY_SERVICE);
142         final List<String> requiredTargets = am.getAccessibilityShortcutTargets(shortcutType);
143         return requiredTargets.contains(componentId);
144     }
145 
146     /**
147      * Converts {@link UserShortcutType} to {@link Settings.Secure} key.
148      *
149      * @param type The shortcut type.
150      * @return Mapping key in Settings.
151      */
convertToKey(@serShortcutType int type)152     public static String convertToKey(@UserShortcutType int type) {
153         switch (type) {
154             case UserShortcutType.SOFTWARE:
155                 return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
156             case UserShortcutType.HARDWARE:
157                 return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
158             case UserShortcutType.TRIPLETAP:
159                 return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
160             default:
161                 throw new IllegalArgumentException(
162                         "Unsupported user shortcut type: " + type);
163         }
164     }
165 
166     /**
167      * Converts {@link ShortcutType} to {@link UserShortcutType}.
168      *
169      * @param type The shortcut type.
170      * @return Mapping type from {@link UserShortcutType}.
171      */
convertToUserType(@hortcutType int type)172     public static @UserShortcutType int convertToUserType(@ShortcutType int type) {
173         switch (type) {
174             case ACCESSIBILITY_BUTTON:
175                 return UserShortcutType.SOFTWARE;
176             case ACCESSIBILITY_SHORTCUT_KEY:
177                 return UserShortcutType.HARDWARE;
178             default:
179                 throw new IllegalArgumentException(
180                         "Unsupported shortcut type:" + type);
181         }
182     }
183 }
184