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 
19 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
20 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
21 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
22 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
23 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
24 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
25 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
26 
27 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
28 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__DISABLED;
29 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__ENABLED;
30 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__UNKNOWN;
31 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
32 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS;
33 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
34 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
35 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP;
36 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
37 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
38 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_ALL;
39 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_FULL_SCREEN;
40 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_UNKNOWN_MODE;
41 import static com.android.internal.util.FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_WINDOW;
42 import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_CLICKED;
43 import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SERVICE_DISABLED;
44 import static com.android.internal.util.FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SHOWN;
45 
46 import android.content.ComponentName;
47 import android.content.Context;
48 import android.provider.Settings;
49 import android.view.accessibility.AccessibilityManager;
50 import android.view.accessibility.AccessibilityManager.ShortcutType;
51 
52 import com.android.internal.util.FrameworkStatsLog;
53 
54 /** Methods for logging accessibility states. */
55 public final class AccessibilityStatsLogUtils {
56     /** The status represents an accessibility privacy warning has been shown. */
57     public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN =
58             NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SHOWN;
59     /** The status represents an accessibility privacy warning has been clicked to review. */
60     public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED =
61             NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_CLICKED;
62     /** The status represents an accessibility privacy warning service has been disabled. */
63     public static int ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED =
64             NON_A11Y_TOOL_SERVICE_WARNING_REPORTED__STATUS__WARNING_SERVICE_DISABLED;
65 
66     private static final int UNKNOWN_STATUS =
67             ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__UNKNOWN;
68 
AccessibilityStatsLogUtils()69     private AccessibilityStatsLogUtils() {}
70 
71     /**
72      * Logs accessibility feature name that is assigned to the given {@code shortcutType}.
73      * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON} or
74      * {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}.
75      *
76      * @param context context used to retrieve the {@link Settings} provider
77      * @param componentName component name of the accessibility feature
78      * @param shortcutType  accessibility shortcut type
79      */
logAccessibilityShortcutActivated(Context context, ComponentName componentName, @ShortcutType int shortcutType)80     public static void logAccessibilityShortcutActivated(Context context,
81             ComponentName componentName, @ShortcutType int shortcutType) {
82         logAccessibilityShortcutActivatedInternal(componentName,
83                 convertToLoggingShortcutType(context, shortcutType), UNKNOWN_STATUS);
84     }
85 
86     /**
87      * Logs accessibility feature name that is assigned to the given {@code shortcutType} and the
88      * {@code serviceEnabled} status.
89      * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON}
90      * or {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}.
91      *
92      * @param context context used to retrieve the {@link Settings} provider
93      * @param componentName  component name of the accessibility feature
94      * @param shortcutType   accessibility shortcut type
95      * @param serviceEnabled {@code true} if the service is enabled
96      */
logAccessibilityShortcutActivated(Context context, ComponentName componentName, @ShortcutType int shortcutType, boolean serviceEnabled)97     public static void logAccessibilityShortcutActivated(Context context,
98             ComponentName componentName, @ShortcutType int shortcutType, boolean serviceEnabled) {
99         logAccessibilityShortcutActivatedInternal(componentName,
100                 convertToLoggingShortcutType(context, shortcutType),
101                 convertToLoggingServiceStatus(serviceEnabled));
102     }
103 
104     /**
105      * Logs accessibility feature name that is assigned to the given {@code loggingShortcutType} and
106      * {@code loggingServiceStatus} code.
107      *
108      * @param componentName        component name of the accessibility feature
109      * @param loggingShortcutType  accessibility shortcut type for logging. 0 denotes
110      *                             unknown_type, 1 denotes accessibility button, 2 denotes volume
111      *                             key, 3 denotes triple tap on the screen, 4 denotes long press on
112      *                             accessibility button, 5 denotes accessibility floating menu.
113      * @param loggingServiceStatus The service status code for logging. 0 denotes unknown_status, 1
114      *                             denotes enabled, 2 denotes disabled.
115      */
logAccessibilityShortcutActivatedInternal(ComponentName componentName, int loggingShortcutType, int loggingServiceStatus)116     private static void logAccessibilityShortcutActivatedInternal(ComponentName componentName,
117             int loggingShortcutType, int loggingServiceStatus) {
118         FrameworkStatsLog.write(FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED,
119                 componentName.flattenToString(), loggingShortcutType, loggingServiceStatus);
120     }
121 
122     /**
123      * Logs magnification that is assigned to the triple tap shortcut. Calls this when triggering
124      * the magnification triple tap shortcut.
125      */
logMagnificationTripleTap(boolean enabled)126     public static void logMagnificationTripleTap(boolean enabled) {
127         FrameworkStatsLog.write(FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED,
128                 MAGNIFICATION_COMPONENT_NAME.flattenToString(),
129                 ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP,
130                 convertToLoggingServiceStatus(enabled));
131     }
132 
133     /**
134      * Logs accessibility feature name that is assigned to the long pressed accessibility button
135      * shortcut. Calls this when clicking the long pressed accessibility button shortcut.
136      *
137      * @param componentName The component name of the accessibility feature.
138      */
logAccessibilityButtonLongPressStatus(ComponentName componentName)139     public static void logAccessibilityButtonLongPressStatus(ComponentName componentName) {
140         FrameworkStatsLog.write(FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED,
141                 componentName.flattenToString(),
142                 ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS,
143                 UNKNOWN_STATUS);
144     }
145 
146     /**
147      * Logs the magnification activated mode and its duration of the usage.
148      * Calls this when the magnification is disabled.
149      *
150      * @param mode The activated magnification mode.
151      * @param duration The duration in milliseconds during the magnification is activated.
152      * @param scale The last magnification scale for the activation
153      */
logMagnificationUsageState(int mode, long duration, float scale)154     public static void logMagnificationUsageState(int mode, long duration, float scale) {
155         FrameworkStatsLog.write(FrameworkStatsLog.MAGNIFICATION_USAGE_REPORTED,
156                 convertToLoggingMagnificationMode(mode),
157                 duration,
158                 convertToLoggingMagnificationScale(scale));
159     }
160 
161     /**
162      * Logs the activated mode of the magnification when the IME window is shown on the screen.
163      * Calls this when the magnification is enabled and the IME window is shown on the screen.
164      *
165      * @param mode The activated magnification mode.
166      */
logMagnificationModeWithImeOn(int mode)167     public static void logMagnificationModeWithImeOn(int mode) {
168         FrameworkStatsLog.write(FrameworkStatsLog.MAGNIFICATION_MODE_WITH_IME_ON_REPORTED,
169                 convertToLoggingMagnificationMode(mode));
170     }
171 
172     /**
173      * Logs the duration for the window magnifier's following typing focus session.
174      *
175      * @param duration The duration of a triple-tap-and-hold activation session.
176      */
logMagnificationFollowTypingFocusSession(long duration)177     public static void logMagnificationFollowTypingFocusSession(long duration) {
178         FrameworkStatsLog.write(
179                 FrameworkStatsLog.MAGNIFICATION_FOLLOW_TYPING_FOCUS_ACTIVATED_SESSION_REPORTED,
180                 duration);
181     }
182 
183     /**
184      * Logs the duration for the magnification session which is activated by the triple tap and
185      * hold gesture.
186      *
187      * @param duration The duration of a triple-tap-and-hold activation session.
188      */
logMagnificationTripleTapAndHoldSession(long duration)189     public static void logMagnificationTripleTapAndHoldSession(long duration) {
190         FrameworkStatsLog.write(
191                 FrameworkStatsLog.MAGNIFICATION_TRIPLE_TAP_AND_HOLD_ACTIVATED_SESSION_REPORTED,
192                 duration);
193     }
194 
195     /**
196      * Logs the warning status of the non-a11yTool service. Calls this when the warning status is
197      * changed.
198      *
199      * @param packageName    The package name of the non-a11yTool service
200      * @param status         The warning status of the non-a11yTool service, it should be one of
201      *                       {@code ACCESSIBILITY_PRIVACY_WARNING_STATUS_SHOWN},{@code
202      *                       ACCESSIBILITY_PRIVACY_WARNING_STATUS_CLICKED} and {@code
203      *                       ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED}
204      * @param durationMillis The duration in milliseconds between current and previous status
205      */
logNonA11yToolServiceWarningReported(String packageName, int status, long durationMillis)206     public static void logNonA11yToolServiceWarningReported(String packageName, int status,
207             long durationMillis) {
208         FrameworkStatsLog.write(FrameworkStatsLog.NON_A11Y_TOOL_SERVICE_WARNING_REPORT,
209                 packageName, status, durationMillis);
210     }
211 
isAccessibilityFloatingMenuEnabled(Context context)212     private static boolean isAccessibilityFloatingMenuEnabled(Context context) {
213         return Settings.Secure.getInt(context.getContentResolver(),
214                 Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
215                 == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
216     }
217 
isAccessibilityGestureEnabled(Context context)218     private static boolean isAccessibilityGestureEnabled(Context context) {
219         return Settings.Secure.getInt(context.getContentResolver(),
220                 Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1)
221                 == ACCESSIBILITY_BUTTON_MODE_GESTURE;
222     }
223 
convertToLoggingShortcutType(Context context, @ShortcutType int shortcutType)224     private static int convertToLoggingShortcutType(Context context,
225             @ShortcutType int shortcutType) {
226         switch (shortcutType) {
227             case ACCESSIBILITY_BUTTON:
228                 if (isAccessibilityFloatingMenuEnabled(context)) {
229                     return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
230                 } else if (isAccessibilityGestureEnabled(context)) {
231                     return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
232                 } else {
233                     return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
234                 }
235             case ACCESSIBILITY_SHORTCUT_KEY:
236                 return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
237         }
238         return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
239     }
240 
convertToLoggingServiceStatus(boolean enabled)241     private static int convertToLoggingServiceStatus(boolean enabled) {
242         return enabled ? ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__ENABLED
243                 : ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__DISABLED;
244     }
245 
convertToLoggingMagnificationMode(int mode)246     private static int convertToLoggingMagnificationMode(int mode) {
247         switch (mode) {
248             case ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN:
249                 return MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_FULL_SCREEN;
250             case ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW:
251                 return MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_WINDOW;
252             case ACCESSIBILITY_MAGNIFICATION_MODE_ALL:
253                 return MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_ALL;
254 
255             default:
256                 return MAGNIFICATION_USAGE_REPORTED__ACTIVATED_MODE__MAGNIFICATION_UNKNOWN_MODE;
257         }
258     }
259 
convertToLoggingMagnificationScale(float scale)260     private static int convertToLoggingMagnificationScale(float scale) {
261         // per b/269366674, we make every 10% a bucket for both privacy and readability concern.
262         // For example
263         // 1. both 2.30f(230%) and 2.36f(236%) would return 230 as bucket id.
264         // 2. bucket id 370 means scale range in [370%, 379%]
265         return ((int) (scale * 10)) * 10;
266     }
267 }
268