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