blob: 82c499a455d784a9dc8a715d8f03cc3e6946ad11 [file] [log] [blame]
Ben Kwa1c0a3892016-01-26 11:50:03 -08001/*
2 * Copyright (C) 2016 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
17package com.android.documentsui;
18
Felipe Lemee4b60122016-02-24 10:17:41 -080019import static android.os.Environment.STANDARD_DIRECTORIES;
Garfield Tan02fd92f2017-01-13 15:28:30 -080020import static com.android.documentsui.DocumentsApplication.acquireUnstableProviderOrThrow;
Steve McKayd9caa6a2016-09-15 16:36:45 -070021import static com.android.documentsui.base.Shared.DEBUG;
Steve McKay15b92782016-03-09 15:20:00 -080022
Ben Kwafaa27202016-01-28 16:39:57 -080023import android.annotation.IntDef;
24import android.annotation.Nullable;
Felipe Lemee4b60122016-02-24 10:17:41 -080025import android.annotation.StringDef;
26import android.app.Activity;
Garfield Tan02fd92f2017-01-13 15:28:30 -080027import android.content.ContentProviderClient;
Ben Kwa1c0a3892016-01-26 11:50:03 -080028import android.content.Context;
29import android.content.Intent;
30import android.content.pm.ResolveInfo;
31import android.net.Uri;
Garfield Tan02fd92f2017-01-13 15:28:30 -080032import android.os.RemoteException;
Ben Kwa1c0a3892016-01-26 11:50:03 -080033import android.provider.DocumentsContract;
Garfield Tan02fd92f2017-01-13 15:28:30 -080034import android.provider.DocumentsContract.Path;
Garfield Tan935c5132017-01-12 14:16:08 -080035import android.provider.DocumentsProvider;
Ben Kwa1c0a3892016-01-26 11:50:03 -080036import android.util.Log;
37
Steve McKayd0805062016-09-15 14:30:38 -070038import com.android.documentsui.base.DocumentInfo;
Steve McKay8659cbc2016-10-31 13:13:36 -070039import com.android.documentsui.base.Providers;
Steve McKayd0805062016-09-15 14:30:38 -070040import com.android.documentsui.base.RootInfo;
Steve McKayd9caa6a2016-09-15 16:36:45 -070041import com.android.documentsui.base.State;
42import com.android.documentsui.base.State.ActionType;
Steve McKayb6006b22016-09-29 09:23:45 -070043import com.android.documentsui.files.LauncherActivity;
Garfield Tan02fd92f2017-01-13 15:28:30 -080044import com.android.documentsui.roots.RootsAccess;
Ben Kwafaa27202016-01-28 16:39:57 -080045import com.android.documentsui.services.FileOperationService;
46import com.android.documentsui.services.FileOperationService.OpType;
Ben Kwa1c0a3892016-01-26 11:50:03 -080047import com.android.internal.logging.MetricsLogger;
Tamas Berghammer0245e6d2016-09-22 18:22:16 +010048import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Ben Kwa1c0a3892016-01-26 11:50:03 -080049
Ben Kwafaa27202016-01-28 16:39:57 -080050import java.lang.annotation.Retention;
51import java.lang.annotation.RetentionPolicy;
52import java.util.List;
53
Ben Kwa1c0a3892016-01-26 11:50:03 -080054/** @hide */
55public final class Metrics {
56 private static final String TAG = "Metrics";
57
Ben Kwa1c0a3892016-01-26 11:50:03 -080058 // These strings have to be whitelisted in tron. Do not change them.
59 private static final String COUNT_LAUNCH_ACTION = "docsui_launch_action";
60 private static final String COUNT_ROOT_VISITED = "docsui_root_visited";
61 private static final String COUNT_OPEN_MIME = "docsui_open_mime";
62 private static final String COUNT_CREATE_MIME = "docsui_create_mime";
63 private static final String COUNT_GET_CONTENT_MIME = "docsui_get_content_mime";
64 private static final String COUNT_BROWSE_ROOT = "docsui_browse_root";
Steve McKay15b92782016-03-09 15:20:00 -080065 @Deprecated private static final String COUNT_MANAGE_ROOT = "docsui_manage_root";
Aga Wronska94e53e42016-04-07 13:09:58 -070066 @Deprecated private static final String COUNT_MULTI_WINDOW = "docsui_multi_window";
Ben Kwafaa27202016-01-28 16:39:57 -080067 private static final String COUNT_FILEOP_SYSTEM = "docsui_fileop_system";
68 private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external";
69 private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled";
Daichi Hirono320a08f2016-03-25 19:04:39 +090070 private static final String COUNT_STARTUP_MS = "docsui_startup_ms";
Aga Wronska441b9be2016-03-29 16:57:10 -070071 private static final String COUNT_DRAWER_OPENED = "docsui_drawer_opened";
Aga Wronska94e53e42016-04-07 13:09:58 -070072 private static final String COUNT_USER_ACTION = "docsui_menu_action";
Garfield Tan935c5132017-01-12 14:16:08 -080073 private static final String COUNT_CREATE_AT_LOCATION = "docsui_create_at_location";
74 private static final String COUNT_OPEN_AT_LOCATION = "docsui_open_at_location";
75 private static final String COUNT_GET_CONTENT_AT_LOCATION = "docsui_get_content_at_location";
Garfield Tan02fd92f2017-01-13 15:28:30 -080076 private static final String COUNT_MEDIA_FILEOP_FAILURE = "docsui_media_fileop_failure";
77 private static final String COUNT_DOWNLOADS_FILEOP_FAILURE = "docsui_downloads_fileop_failure";
78 private static final String COUNT_INTERNAL_STORAGE_FILEOP_FAILURE
79 = "docsui_internal_storage_fileop_failure";
80 private static final String COUNT_EXTERNAL_STORAGE_FILEOP_FAILURE
81 = "docsui_external_storage_fileop_failure";
82 private static final String COUNT_MTP_FILEOP_FAILURE = "docsui_mtp_fileop_failure";
83 private static final String COUNT_OTHER_FILEOP_FAILURE = "docsui_other_fileop_failure";
Ben Kwa1c0a3892016-01-26 11:50:03 -080084
85 // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
86 // root that is not explicitly recognized by the Metrics code (see {@link
Ben Kwab41a5ed2016-02-17 16:06:22 -080087 // #getSanitizedRootIndex}). Apps are also bucketed in this histogram.
Ben Kwaebaaea42016-01-28 18:15:07 -080088 // Do not change or rearrange these values, that will break historical data. Only add to the end
89 // of the list.
Ben Kwab41a5ed2016-02-17 16:06:22 -080090 // Do not use negative numbers or zero; clearcut only handles positive integers.
91 private static final int ROOT_NONE = 1;
92 private static final int ROOT_OTHER = 2;
93 private static final int ROOT_AUDIO = 3;
94 private static final int ROOT_DEVICE_STORAGE = 4;
95 private static final int ROOT_DOWNLOADS = 5;
96 private static final int ROOT_HOME = 6;
97 private static final int ROOT_IMAGES = 7;
98 private static final int ROOT_RECENTS = 8;
99 private static final int ROOT_VIDEOS = 9;
100 private static final int ROOT_MTP = 10;
Ben Kwa1c0a3892016-01-26 11:50:03 -0800101 // Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
Ben Kwab41a5ed2016-02-17 16:06:22 -0800102 // are logged analogously to roots.
103 private static final int ROOT_THIRD_PARTY_APP = 100;
Ben Kwa1c0a3892016-01-26 11:50:03 -0800104
Ben Kwafaa27202016-01-28 16:39:57 -0800105 @IntDef(flag = true, value = {
106 ROOT_NONE,
107 ROOT_OTHER,
108 ROOT_AUDIO,
109 ROOT_DEVICE_STORAGE,
110 ROOT_DOWNLOADS,
111 ROOT_HOME,
112 ROOT_IMAGES,
113 ROOT_RECENTS,
114 ROOT_VIDEOS,
Ben Kwaebaaea42016-01-28 18:15:07 -0800115 ROOT_MTP,
Ben Kwafaa27202016-01-28 16:39:57 -0800116 ROOT_THIRD_PARTY_APP
117 })
118 @Retention(RetentionPolicy.SOURCE)
119 public @interface Root {}
120
Ben Kwa1c0a3892016-01-26 11:50:03 -0800121 // Indices for bucketing mime types.
Ben Kwab41a5ed2016-02-17 16:06:22 -0800122 // Do not change or rearrange these values, that will break historical data. Only add to the end
123 // of the list.
124 // Do not use negative numbers or zero; clearcut only handles positive integers.
125 private static final int MIME_NONE = 1; // null mime
126 private static final int MIME_ANY = 2; // */*
127 private static final int MIME_APPLICATION = 3; // application/*
128 private static final int MIME_AUDIO = 4; // audio/*
129 private static final int MIME_IMAGE = 5; // image/*
130 private static final int MIME_MESSAGE = 6; // message/*
131 private static final int MIME_MULTIPART = 7; // multipart/*
132 private static final int MIME_TEXT = 8; // text/*
133 private static final int MIME_VIDEO = 9; // video/*
134 private static final int MIME_OTHER = 10; // anything not enumerated below
Ben Kwa1c0a3892016-01-26 11:50:03 -0800135
Ben Kwafaa27202016-01-28 16:39:57 -0800136 @IntDef(flag = true, value = {
Ben Kwafaa27202016-01-28 16:39:57 -0800137 MIME_NONE,
138 MIME_ANY,
139 MIME_APPLICATION,
140 MIME_AUDIO,
141 MIME_IMAGE,
142 MIME_MESSAGE,
143 MIME_MULTIPART,
144 MIME_TEXT,
Ben Kwab41a5ed2016-02-17 16:06:22 -0800145 MIME_VIDEO,
146 MIME_OTHER
Ben Kwafaa27202016-01-28 16:39:57 -0800147 })
148 @Retention(RetentionPolicy.SOURCE)
149 public @interface Mime {}
150
151 // Codes representing different kinds of file operations. These are used for bucketing
152 // operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms.
Ben Kwab41a5ed2016-02-17 16:06:22 -0800153 // Do not change or rearrange these values, that will break historical data. Only add to the
154 // list.
155 // Do not use negative numbers or zero; clearcut only handles positive integers.
156 private static final int FILEOP_OTHER = 1; // any file operation not listed below
157 private static final int FILEOP_COPY_INTRA_PROVIDER = 2; // Copy within a provider
158 private static final int FILEOP_COPY_SYSTEM_PROVIDER = 3; // Copy to a system provider.
159 private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 4; // Copy to a 3rd-party provider.
160 private static final int FILEOP_MOVE_INTRA_PROVIDER = 5; // Move within a provider.
161 private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 6; // Move to a system provider.
162 private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 7; // Move to a 3rd-party provider.
163 private static final int FILEOP_DELETE = 8;
Aga Wronska46a868a2016-03-30 10:57:04 -0700164 private static final int FILEOP_RENAME = 9;
165 private static final int FILEOP_CREATE_DIR = 10;
Ben Kwab41a5ed2016-02-17 16:06:22 -0800166 private static final int FILEOP_OTHER_ERROR = 100;
167 private static final int FILEOP_DELETE_ERROR = 101;
168 private static final int FILEOP_MOVE_ERROR = 102;
169 private static final int FILEOP_COPY_ERROR = 103;
Aga Wronska46a868a2016-03-30 10:57:04 -0700170 private static final int FILEOP_RENAME_ERROR = 104;
171 private static final int FILEOP_CREATE_DIR_ERROR = 105;
Ben Kwafaa27202016-01-28 16:39:57 -0800172
173 @IntDef(flag = true, value = {
174 FILEOP_OTHER,
175 FILEOP_COPY_INTRA_PROVIDER,
176 FILEOP_COPY_SYSTEM_PROVIDER,
177 FILEOP_COPY_EXTERNAL_PROVIDER,
178 FILEOP_MOVE_INTRA_PROVIDER,
179 FILEOP_MOVE_SYSTEM_PROVIDER,
180 FILEOP_MOVE_EXTERNAL_PROVIDER,
181 FILEOP_DELETE,
Aga Wronska46a868a2016-03-30 10:57:04 -0700182 FILEOP_RENAME,
183 FILEOP_CREATE_DIR,
Ben Kwafaa27202016-01-28 16:39:57 -0800184 FILEOP_OTHER_ERROR,
185 FILEOP_COPY_ERROR,
186 FILEOP_MOVE_ERROR,
Aga Wronska46a868a2016-03-30 10:57:04 -0700187 FILEOP_DELETE_ERROR,
188 FILEOP_RENAME_ERROR,
189 FILEOP_CREATE_DIR_ERROR
Ben Kwafaa27202016-01-28 16:39:57 -0800190 })
191 @Retention(RetentionPolicy.SOURCE)
192 public @interface FileOp {}
193
Ben Kwab41a5ed2016-02-17 16:06:22 -0800194 // Codes representing different kinds of file operations. These are used for bucketing
195 // operations in the COUNT_FILEOP_CANCELED histogram.
196 // Do not change or rearrange these values, that will break historical data. Only add to the
197 // list.
198 // Do not use negative numbers or zero; clearcut only handles positive integers.
199 private static final int OPERATION_UNKNOWN = 1;
200 private static final int OPERATION_COPY = 2;
201 private static final int OPERATION_MOVE = 3;
202 private static final int OPERATION_DELETE= 4;
203
204 @IntDef(flag = true, value = {
205 OPERATION_UNKNOWN,
206 OPERATION_COPY,
207 OPERATION_MOVE,
208 OPERATION_DELETE
209 })
210 @Retention(RetentionPolicy.SOURCE)
211 public @interface MetricsOpType {}
212
Aga Wronska4972d712016-03-30 13:55:19 -0700213 // Codes representing different provider types. Used for sorting file operations when logging.
214 private static final int PROVIDER_INTRA = 0;
215 private static final int PROVIDER_SYSTEM = 1;
216 private static final int PROVIDER_EXTERNAL = 2;
217
218 @IntDef(flag = false, value = {
219 PROVIDER_INTRA,
220 PROVIDER_SYSTEM,
221 PROVIDER_EXTERNAL
222 })
223 @Retention(RetentionPolicy.SOURCE)
224 public @interface Provider {}
225
Garfield Tan02fd92f2017-01-13 15:28:30 -0800226 // Codes representing different types of sub-fileops. These are used for bucketing fileop
227 // failures in COUNT_*_FILEOP_FAILURE.
228 public static final int SUBFILEOP_QUERY_DOCUMENT = 1;
229 public static final int SUBFILEOP_QUERY_CHILDREN = 2;
230 public static final int SUBFILEOP_OPEN_FILE = 3;
231 public static final int SUBFILEOP_READ_FILE = 4;
232 public static final int SUBFILEOP_CREATE_DOCUMENT = 5;
233 public static final int SUBFILEOP_WRITE_FILE = 6;
234 public static final int SUBFILEOP_DELETE_DOCUMENT = 7;
235 public static final int SUBFILEOP_OBTAIN_STREAM_TYPE = 8;
236 public static final int SUBFILEOP_QUICK_MOVE = 9;
237 public static final int SUBFILEOP_QUICK_COPY = 10;
238
239 @IntDef(flag = false, value = {
240 SUBFILEOP_QUERY_DOCUMENT,
241 SUBFILEOP_QUERY_CHILDREN,
242 SUBFILEOP_OPEN_FILE,
243 SUBFILEOP_READ_FILE,
244 SUBFILEOP_CREATE_DOCUMENT,
245 SUBFILEOP_WRITE_FILE,
246 SUBFILEOP_DELETE_DOCUMENT,
247 SUBFILEOP_OBTAIN_STREAM_TYPE,
248 SUBFILEOP_QUICK_MOVE,
249 SUBFILEOP_QUICK_COPY
250 })
251 @Retention(RetentionPolicy.SOURCE)
252 public @interface SubFileOp {}
Aga Wronska4972d712016-03-30 13:55:19 -0700253
Aga Wronska94e53e42016-04-07 13:09:58 -0700254 // Codes representing different user actions. These are used for bucketing stats in the
255 // COUNT_USER_ACTION histogram.
256 // The historgram includes action triggered from menu or invoked by keyboard shortcut.
Aga Wronska4972d712016-03-30 13:55:19 -0700257 // Do not change or rearrange these values, that will break historical data. Only add to the
258 // list.
259 // Do not use negative numbers or zero; clearcut only handles positive integers.
Aga Wronska94e53e42016-04-07 13:09:58 -0700260 public static final int USER_ACTION_OTHER = 1;
261 public static final int USER_ACTION_GRID = 2;
262 public static final int USER_ACTION_LIST = 3;
263 public static final int USER_ACTION_SORT_NAME = 4;
264 public static final int USER_ACTION_SORT_DATE = 5;
265 public static final int USER_ACTION_SORT_SIZE = 6;
266 public static final int USER_ACTION_SEARCH = 7;
267 public static final int USER_ACTION_SHOW_SIZE = 8;
268 public static final int USER_ACTION_HIDE_SIZE = 9;
269 public static final int USER_ACTION_SETTINGS = 10;
270 public static final int USER_ACTION_COPY_TO = 11;
271 public static final int USER_ACTION_MOVE_TO = 12;
272 public static final int USER_ACTION_DELETE = 13;
273 public static final int USER_ACTION_RENAME = 14;
274 public static final int USER_ACTION_CREATE_DIR = 15;
275 public static final int USER_ACTION_SELECT_ALL = 16;
276 public static final int USER_ACTION_SHARE = 17;
277 public static final int USER_ACTION_OPEN = 18;
278 public static final int USER_ACTION_SHOW_ADVANCED = 19;
279 public static final int USER_ACTION_HIDE_ADVANCED = 20;
280 public static final int USER_ACTION_NEW_WINDOW = 21;
281 public static final int USER_ACTION_PASTE_CLIPBOARD = 22;
282 public static final int USER_ACTION_COPY_CLIPBOARD = 23;
283 public static final int USER_ACTION_DRAG_N_DROP = 24;
284 public static final int USER_ACTION_DRAG_N_DROP_MULTI_WINDOW = 25;
Ben Linff4d5842016-04-18 14:35:28 -0700285 public static final int USER_ACTION_CUT_CLIPBOARD = 26;
Aga Wronska4972d712016-03-30 13:55:19 -0700286
287 @IntDef(flag = false, value = {
Aga Wronska94e53e42016-04-07 13:09:58 -0700288 USER_ACTION_OTHER,
289 USER_ACTION_GRID,
290 USER_ACTION_LIST,
291 USER_ACTION_SORT_NAME,
292 USER_ACTION_SORT_DATE,
293 USER_ACTION_SORT_SIZE,
294 USER_ACTION_SEARCH,
295 USER_ACTION_SHOW_SIZE,
296 USER_ACTION_HIDE_SIZE,
297 USER_ACTION_SETTINGS,
298 USER_ACTION_COPY_TO,
299 USER_ACTION_MOVE_TO,
300 USER_ACTION_DELETE,
301 USER_ACTION_RENAME,
302 USER_ACTION_CREATE_DIR,
303 USER_ACTION_SELECT_ALL,
304 USER_ACTION_SHARE,
305 USER_ACTION_OPEN,
306 USER_ACTION_SHOW_ADVANCED,
307 USER_ACTION_HIDE_ADVANCED,
308 USER_ACTION_NEW_WINDOW,
309 USER_ACTION_PASTE_CLIPBOARD,
310 USER_ACTION_COPY_CLIPBOARD,
311 USER_ACTION_DRAG_N_DROP,
Ben Linff4d5842016-04-18 14:35:28 -0700312 USER_ACTION_DRAG_N_DROP_MULTI_WINDOW,
313 USER_ACTION_CUT_CLIPBOARD
Aga Wronska4972d712016-03-30 13:55:19 -0700314 })
315 @Retention(RetentionPolicy.SOURCE)
Aga Wronska94e53e42016-04-07 13:09:58 -0700316 public @interface UserAction {}
Aga Wronska4972d712016-03-30 13:55:19 -0700317
318 // Codes representing different menu actions. These are used for bucketing stats in the
319 // COUNT_MENU_ACTION histogram.
Ben Kwab41a5ed2016-02-17 16:06:22 -0800320 // Do not change or rearrange these values, that will break historical data. Only add to the
321 // list.
322 // Do not use negative numbers or zero; clearcut only handles positive integers.
323 private static final int ACTION_OTHER = 1;
324 private static final int ACTION_OPEN = 2;
325 private static final int ACTION_CREATE = 3;
326 private static final int ACTION_GET_CONTENT = 4;
327 private static final int ACTION_OPEN_TREE = 5;
Steve McKay15b92782016-03-09 15:20:00 -0800328 @Deprecated private static final int ACTION_MANAGE = 6;
Ben Kwab41a5ed2016-02-17 16:06:22 -0800329 private static final int ACTION_BROWSE = 7;
330 private static final int ACTION_PICK_COPY_DESTINATION = 8;
331
332 @IntDef(flag = true, value = {
333 ACTION_OTHER,
334 ACTION_OPEN,
335 ACTION_CREATE,
336 ACTION_GET_CONTENT,
337 ACTION_OPEN_TREE,
338 ACTION_MANAGE,
339 ACTION_BROWSE,
340 ACTION_PICK_COPY_DESTINATION
341 })
342 @Retention(RetentionPolicy.SOURCE)
343 public @interface MetricsAction {}
344
Aga Wronska441b9be2016-03-29 16:57:10 -0700345 // Codes representing different actions to open the drawer. They are used for bucketing stats in
346 // the COUNT_DRAWER_OPENED histogram.
347 // Do not change or rearrange these values, that will break historical data. Only add to the
348 // list.
349 // Do not use negative numbers or zero; clearcut only handles positive integers.
350 private static final int DRAWER_OPENED_HAMBURGER = 1;
351 private static final int DRAWER_OPENED_SWIPE = 2;
352
353 @IntDef(flag = true, value = {
354 DRAWER_OPENED_HAMBURGER,
355 DRAWER_OPENED_SWIPE
356 })
357 @Retention(RetentionPolicy.SOURCE)
358 public @interface DrawerTrigger {}
359
Ben Kwa1c0a3892016-01-26 11:50:03 -0800360 /**
361 * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
362 *
363 * @param context
364 * @param state
365 * @param intent
366 */
367 public static void logActivityLaunch(Context context, State state, Intent intent) {
368 // Log the launch action.
Ben Kwab41a5ed2016-02-17 16:06:22 -0800369 logHistogram(context, COUNT_LAUNCH_ACTION, toMetricsAction(state.action));
Ben Kwa1c0a3892016-01-26 11:50:03 -0800370 // Then log auxiliary data (roots/mime types) associated with some actions.
371 Uri uri = intent.getData();
372 switch (state.action) {
373 case State.ACTION_OPEN:
374 logHistogram(context, COUNT_OPEN_MIME, sanitizeMime(intent.getType()));
375 break;
376 case State.ACTION_CREATE:
377 logHistogram(context, COUNT_CREATE_MIME, sanitizeMime(intent.getType()));
378 break;
379 case State.ACTION_GET_CONTENT:
380 logHistogram(context, COUNT_GET_CONTENT_MIME, sanitizeMime(intent.getType()));
381 break;
Ben Kwa1c0a3892016-01-26 11:50:03 -0800382 case State.ACTION_BROWSE:
383 logHistogram(context, COUNT_BROWSE_ROOT, sanitizeRoot(uri));
384 break;
385 default:
386 break;
387 }
388 }
389
390 /**
Garfield Tan935c5132017-01-12 14:16:08 -0800391 * Logs when DocumentsUI are launched with {@link DocumentsContract#EXTRA_INITIAL_URI}.
392 *
393 * @param context
394 * @param state used to resolve action
395 * @param rootUri the resolved rootUri, or {@code null} if the provider doesn't
396 * support {@link DocumentsProvider#findDocumentPath(String, String)}
397 */
398 public static void logLaunchAtLocation(Context context, State state, @Nullable Uri rootUri) {
399 switch (state.action) {
400 case State.ACTION_CREATE:
401 logHistogram(context, COUNT_CREATE_AT_LOCATION, sanitizeRoot(rootUri));
402 break;
403 case State.ACTION_GET_CONTENT:
404 logHistogram(context, COUNT_GET_CONTENT_AT_LOCATION, sanitizeRoot(rootUri));
405 break;
406 case State.ACTION_OPEN:
407 logHistogram(context, COUNT_OPEN_AT_LOCATION, sanitizeRoot(rootUri));
408 break;
409 }
410 }
411
412 /**
Garfield, Tan804133e2016-04-20 15:13:56 -0700413 * Logs a root visited event. Call this when the user visits on a root in the RootsFragment.
Ben Kwa1c0a3892016-01-26 11:50:03 -0800414 *
415 * @param context
416 * @param info
417 */
418 public static void logRootVisited(Context context, RootInfo info) {
419 logHistogram(context, COUNT_ROOT_VISITED, sanitizeRoot(info));
420 }
421
422 /**
Garfield, Tan804133e2016-04-20 15:13:56 -0700423 * Logs an app visited event. Call this when the user visits on an app in the RootsFragment.
Ben Kwa1c0a3892016-01-26 11:50:03 -0800424 *
425 * @param context
426 * @param info
427 */
428 public static void logAppVisited(Context context, ResolveInfo info) {
429 logHistogram(context, COUNT_ROOT_VISITED, sanitizeRoot(info));
430 }
431
432 /**
Aga Wronska441b9be2016-03-29 16:57:10 -0700433 * Logs a drawer opened event. Call this when the user opens drawer by swipe or by clicking the
434 * hamburger icon.
435 * @param context
436 * @param trigger type of action that opened the drawer
437 */
438 public static void logDrawerOpened(Context context, @DrawerController.Trigger int trigger) {
439 if (trigger == DrawerController.OPENED_HAMBURGER) {
440 logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_HAMBURGER);
441 } else if (trigger == DrawerController.OPENED_SWIPE) {
442 logHistogram(context, COUNT_DRAWER_OPENED, DRAWER_OPENED_SWIPE);
443 }
444 }
445
446 /**
Ben Kwafaa27202016-01-28 16:39:57 -0800447 * Logs file operation stats. Call this when a file operation has completed. The given
448 * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one
449 * provider to another vs copying within a given provider). No PII is logged.
450 *
451 * @param context
452 * @param operationType
453 * @param srcs
454 * @param dst
455 */
456 public static void logFileOperation(
457 Context context,
458 @OpType int operationType,
459 List<DocumentInfo> srcs,
460 @Nullable DocumentInfo dst) {
Steve McKay99f1dc32016-12-29 16:02:01 -0800461
462 ProviderCounts counts = new ProviderCounts();
463 countProviders(counts, srcs, dst);
Ben Kwafaa27202016-01-28 16:39:57 -0800464
465 if (counts.intraProvider > 0) {
466 logIntraProviderFileOps(context, dst.authority, operationType);
467 }
468 if (counts.systemProvider > 0) {
469 // Log file operations on system providers.
470 logInterProviderFileOps(context, COUNT_FILEOP_SYSTEM, dst, operationType);
471 }
472 if (counts.externalProvider > 0) {
473 // Log file operations on external providers.
474 logInterProviderFileOps(context, COUNT_FILEOP_EXTERNAL, dst, operationType);
475 }
476 }
477
478 /**
Aga Wronska46a868a2016-03-30 10:57:04 -0700479 * Logs create directory operation. It is a part of file operation stats. We do not
480 * differentiate between internal and external locations, all create directory operations are
481 * logged under COUNT_FILEOP_SYSTEM. Call this when a create directory operation has completed.
482 *
483 * @param context
484 */
485 public static void logCreateDirOperation(Context context) {
486 logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR);
487 }
488
489 /**
490 * Logs rename file operation. It is a part of file operation stats. We do not differentiate
491 * between internal and external locations, all rename operations are logged under
492 * COUNT_FILEOP_SYSTEM. Call this when a rename file operation has completed.
493 *
494 * @param context
495 */
496 public static void logRenameFileOperation(Context context) {
497 logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME);
498 }
499
500 /**
Ben Kwafaa27202016-01-28 16:39:57 -0800501 * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete)
502 * fails.
503 *
504 * @param context
505 * @param operationType
506 * @param failedFiles
507 */
508 public static void logFileOperationErrors(Context context, @OpType int operationType,
Steve McKay99f1dc32016-12-29 16:02:01 -0800509 List<DocumentInfo> failedFiles, List<Uri> failedUris) {
510
511 ProviderCounts counts = new ProviderCounts();
512 countProviders(counts, failedFiles, null);
513
514 // TODO: Report URI errors separate from file operation errors.
515 countProviders(counts, failedUris);
Ben Kwafaa27202016-01-28 16:39:57 -0800516
517 @FileOp int opCode = FILEOP_OTHER_ERROR;
518 switch (operationType) {
519 case FileOperationService.OPERATION_COPY:
520 opCode = FILEOP_COPY_ERROR;
521 break;
522 case FileOperationService.OPERATION_DELETE:
523 opCode = FILEOP_DELETE_ERROR;
524 break;
525 case FileOperationService.OPERATION_MOVE:
526 opCode = FILEOP_MOVE_ERROR;
527 break;
528 }
529 if (counts.systemProvider > 0) {
530 logHistogram(context, COUNT_FILEOP_SYSTEM, opCode);
531 }
532 if (counts.externalProvider > 0) {
533 logHistogram(context, COUNT_FILEOP_EXTERNAL, opCode);
534 }
535 }
536
Garfield Tan02fd92f2017-01-13 15:28:30 -0800537 public static void logFileOperationFailure(
538 Context context, @SubFileOp int subFileOp, Uri docUri) {
539 final String authority = docUri.getAuthority();
540 switch (authority) {
541 case Providers.AUTHORITY_MEDIA:
542 logHistogram(context, COUNT_MEDIA_FILEOP_FAILURE, subFileOp);
543 break;
544 case Providers.AUTHORITY_STORAGE:
545 logStorageFileOperationFailure(context, subFileOp, docUri);
546 break;
547 case Providers.AUTHORITY_DOWNLOADS:
548 logHistogram(context, COUNT_DOWNLOADS_FILEOP_FAILURE, subFileOp);
549 break;
550 case Providers.AUTHORITY_MTP:
551 logHistogram(context, COUNT_MTP_FILEOP_FAILURE, subFileOp);
552 break;
553 default:
554 logHistogram(context, COUNT_OTHER_FILEOP_FAILURE, subFileOp);
555 break;
556 }
557 }
558
Ben Kwafaa27202016-01-28 16:39:57 -0800559 /**
Aga Wronska46a868a2016-03-30 10:57:04 -0700560 * Logs create directory operation error. We do not differentiate between internal and external
561 * locations, all create directory errors are logged under COUNT_FILEOP_SYSTEM. Call this when a
562 * create directory operation fails.
563 *
564 * @param context
565 */
566 public static void logCreateDirError(Context context) {
Aga Wronska94e53e42016-04-07 13:09:58 -0700567 logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_CREATE_DIR_ERROR);
Aga Wronska46a868a2016-03-30 10:57:04 -0700568 }
569
570 /**
571 * Logs rename file operation error. We do not differentiate between internal and external
572 * locations, all rename errors are logged under COUNT_FILEOP_SYSTEM. Call this
573 * when a rename file operation fails.
574 *
575 * @param context
576 */
577 public static void logRenameFileError(Context context) {
578 logHistogram(context, COUNT_FILEOP_SYSTEM, FILEOP_RENAME_ERROR);
579 }
580
581 /**
Daichi Hirono320a08f2016-03-25 19:04:39 +0900582 * Logs the cancellation of a file operation. Call this when a Job is canceled.
Ben Kwafaa27202016-01-28 16:39:57 -0800583 * @param context
584 * @param operationType
585 */
586 public static void logFileOperationCancelled(Context context, @OpType int operationType) {
Ben Kwab41a5ed2016-02-17 16:06:22 -0800587 logHistogram(context, COUNT_FILEOP_CANCELED, toMetricsOpType(operationType));
Ben Kwafaa27202016-01-28 16:39:57 -0800588 }
589
Daichi Hirono320a08f2016-03-25 19:04:39 +0900590 /**
591 * Logs startup time in milliseconds.
592 * @param context
593 * @param startupMs Startup time in milliseconds.
594 */
595 public static void logStartupMs(Context context, int startupMs) {
596 logHistogram(context, COUNT_STARTUP_MS, startupMs);
597 }
598
Ben Kwafaa27202016-01-28 16:39:57 -0800599 private static void logInterProviderFileOps(
600 Context context,
601 String histogram,
602 DocumentInfo dst,
603 @OpType int operationType) {
604 if (operationType == FileOperationService.OPERATION_DELETE) {
605 logHistogram(context, histogram, FILEOP_DELETE);
606 } else {
Steve McKay0af8afd2016-02-25 13:34:03 -0800607 assert(dst != null);
Ben Kwafaa27202016-01-28 16:39:57 -0800608 @Provider int providerType =
609 isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL;
610 logHistogram(context, histogram, getOpCode(operationType, providerType));
611 }
612 }
613
614 private static void logIntraProviderFileOps(
615 Context context, String authority, @OpType int operationType) {
616 // Find the right histogram to log to, then log the operation.
617 String histogram = isSystemProvider(authority) ? COUNT_FILEOP_SYSTEM : COUNT_FILEOP_EXTERNAL;
618 logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
619 }
620
Felipe Lemee4b60122016-02-24 10:17:41 -0800621 // Types for logInvalidScopedAccessRequest
622 public static final String SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS =
Ben Lin5e5cae12016-05-26 16:17:59 -0700623 "docsui_scoped_directory_access_invalid_args";
Felipe Lemee4b60122016-02-24 10:17:41 -0800624 public static final String SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY =
Ben Lin5e5cae12016-05-26 16:17:59 -0700625 "docsui_scoped_directory_access_invalid_dir";
Felipe Lemee4b60122016-02-24 10:17:41 -0800626 public static final String SCOPED_DIRECTORY_ACCESS_ERROR =
Ben Lin5e5cae12016-05-26 16:17:59 -0700627 "docsui_scoped_directory_access_error";
Felipe Lemee4b60122016-02-24 10:17:41 -0800628
629 @StringDef(value = {
630 SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS,
631 SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY,
632 SCOPED_DIRECTORY_ACCESS_ERROR
633 })
634 @Retention(RetentionPolicy.SOURCE)
635 public @interface InvalidScopedAccess{}
636
637 public static void logInvalidScopedAccessRequest(Context context,
638 @InvalidScopedAccess String type) {
Felipe Lemee4b60122016-02-24 10:17:41 -0800639 switch (type) {
640 case SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS:
641 case SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY:
642 case SCOPED_DIRECTORY_ACCESS_ERROR:
Ben Lin6e5a77b2016-05-06 12:30:13 -0700643 logCount(context, type);
Felipe Lemee4b60122016-02-24 10:17:41 -0800644 break;
645 default:
646 Log.wtf(TAG, "invalid InvalidScopedAccess: " + type);
647 }
648 }
649
650 // Types for logValidScopedAccessRequest
651 public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED = 0;
652 public static final int SCOPED_DIRECTORY_ACCESS_GRANTED = 1;
653 public static final int SCOPED_DIRECTORY_ACCESS_DENIED = 2;
Felipe Leme0bdb7c32016-03-09 17:40:49 -0800654 public static final int SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST = 3;
655 public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED = 4;
Felipe Lemee4b60122016-02-24 10:17:41 -0800656
657 @IntDef(flag = true, value = {
658 SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED,
659 SCOPED_DIRECTORY_ACCESS_GRANTED,
Felipe Leme0bdb7c32016-03-09 17:40:49 -0800660 SCOPED_DIRECTORY_ACCESS_DENIED,
661 SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST,
662 SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED
Felipe Lemee4b60122016-02-24 10:17:41 -0800663 })
664 @Retention(RetentionPolicy.SOURCE)
665 public @interface ScopedAccessGrant {}
666
667 public static void logValidScopedAccessRequest(Activity activity, String directory,
668 @ScopedAccessGrant int type) {
669 int index = -1;
Felipe Lemeb59a8a62016-03-17 18:56:20 -0700670 if (OpenExternalDirectoryActivity.DIRECTORY_ROOT.equals(directory)) {
671 index = -2;
672 } else {
673 for (int i = 0; i < STANDARD_DIRECTORIES.length; i++) {
674 if (STANDARD_DIRECTORIES[i].equals(directory)) {
675 index = i;
676 break;
677 }
Felipe Lemee4b60122016-02-24 10:17:41 -0800678 }
679 }
680 final String packageName = activity.getCallingPackage();
681 switch (type) {
682 case SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED:
Felipe Leme0bdb7c32016-03-09 17:40:49 -0800683 MetricsLogger.action(activity, MetricsEvent
684 .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE, packageName);
685 MetricsLogger.action(activity, MetricsEvent
686 .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER, index);
Felipe Lemee4b60122016-02-24 10:17:41 -0800687 break;
688 case SCOPED_DIRECTORY_ACCESS_GRANTED:
Felipe Leme0bdb7c32016-03-09 17:40:49 -0800689 MetricsLogger.action(activity, MetricsEvent
690 .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE, packageName);
691 MetricsLogger.action(activity, MetricsEvent
692 .ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER, index);
Felipe Lemee4b60122016-02-24 10:17:41 -0800693 break;
694 case SCOPED_DIRECTORY_ACCESS_DENIED:
Felipe Leme0bdb7c32016-03-09 17:40:49 -0800695 MetricsLogger.action(activity, MetricsEvent
696 .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE, packageName);
697 MetricsLogger.action(activity, MetricsEvent
698 .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER, index);
699 break;
700 case SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST:
701 MetricsLogger.action(activity, MetricsEvent
702 .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE, packageName);
703 MetricsLogger.action(activity, MetricsEvent
704 .ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_FOLDER, index);
705 break;
706 case SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED:
707 MetricsLogger.action(activity, MetricsEvent
708 .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_PACKAGE, packageName);
709 MetricsLogger.action(activity, MetricsEvent
710 .ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_DENIED_BY_FOLDER, index);
Felipe Lemee4b60122016-02-24 10:17:41 -0800711 break;
712 default:
713 Log.wtf(TAG, "invalid ScopedAccessGrant: " + type);
714 }
715 }
716
Ben Kwafaa27202016-01-28 16:39:57 -0800717 /**
Aga Wronska94e53e42016-04-07 13:09:58 -0700718 * Logs the action that was started by user.
Aga Wronska4972d712016-03-30 13:55:19 -0700719 * @param context
Aga Wronska94e53e42016-04-07 13:09:58 -0700720 * @param userAction
Aga Wronska4972d712016-03-30 13:55:19 -0700721 */
Aga Wronska94e53e42016-04-07 13:09:58 -0700722 public static void logUserAction(Context context, @UserAction int userAction) {
723 logHistogram(context, COUNT_USER_ACTION, userAction);
Aga Wronska4972d712016-03-30 13:55:19 -0700724 }
725
Garfield Tan02fd92f2017-01-13 15:28:30 -0800726 private static void logStorageFileOperationFailure(
727 Context context, @SubFileOp int subFileOp, Uri docUri) {
728 assert(Providers.AUTHORITY_STORAGE.equals(docUri.getAuthority()));
729
730 boolean isInternal;
731 try (ContentProviderClient client = acquireUnstableProviderOrThrow(
732 context.getContentResolver(), Providers.AUTHORITY_STORAGE)) {
733 final Path path = DocumentsContract.findDocumentPath(client, docUri);
734
735 final RootsAccess roots = DocumentsApplication.getRootsCache(context);
736 final RootInfo root = roots.getRootOneshot(
737 Providers.AUTHORITY_STORAGE, path.getRootId());
738 isInternal = !root.supportsEject();
739 } catch (RemoteException | RuntimeException e) {
740 Log.e(TAG, "Failed to obtain its root info. Log the metrics as internal.", e);
741 // It's not very likely to have an external storage so log it as internal.
742 isInternal = true;
743 }
744
745 final String histogram = isInternal
746 ? COUNT_INTERNAL_STORAGE_FILEOP_FAILURE
747 : COUNT_EXTERNAL_STORAGE_FILEOP_FAILURE;
748 logHistogram(context, histogram, subFileOp);
749 }
750
Aga Wronska4972d712016-03-30 13:55:19 -0700751 /**
Ben Kwa1c0a3892016-01-26 11:50:03 -0800752 * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
753 *
754 * @param context
755 * @param name The counter to increment.
756 */
757 private static void logCount(Context context, String name) {
758 if (DEBUG) Log.d(TAG, name + ": " + 1);
759 MetricsLogger.count(context, name, 1);
760 }
761
762 /**
763 * Internal method for making a MetricsLogger.histogram call.
764 *
765 * @param context
766 * @param name The name of the histogram.
767 * @param bucket The bucket to increment.
768 */
Aga Wronska6d50bcc2016-03-28 17:27:02 -0700769 private static void logHistogram(Context context, String name, @ActionType int bucket) {
Ben Kwa1c0a3892016-01-26 11:50:03 -0800770 if (DEBUG) Log.d(TAG, name + ": " + bucket);
771 MetricsLogger.histogram(context, name, bucket);
772 }
773
774 /**
775 * Generates an integer identifying the given root. For privacy, this function only recognizes a
776 * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into
777 * a single ROOT_OTHER bucket.
778 */
Ben Kwafaa27202016-01-28 16:39:57 -0800779 private static @Root int sanitizeRoot(Uri uri) {
Tomasz Mikolajewski63e2aae2016-02-01 12:01:14 +0900780 if (uri == null || uri.getAuthority() == null || LauncherActivity.isLaunchUri(uri)) {
Ben Kwa1c0a3892016-01-26 11:50:03 -0800781 return ROOT_NONE;
782 }
783
784 switch (uri.getAuthority()) {
Steve McKay8659cbc2016-10-31 13:13:36 -0700785 case Providers.AUTHORITY_MEDIA:
Ben Kwa1c0a3892016-01-26 11:50:03 -0800786 switch (DocumentsContract.getRootId(uri)) {
Steve McKay8659cbc2016-10-31 13:13:36 -0700787 case Providers.ROOT_ID_AUDIO:
Ben Kwa1c0a3892016-01-26 11:50:03 -0800788 return ROOT_AUDIO;
Steve McKay8659cbc2016-10-31 13:13:36 -0700789 case Providers.ROOT_ID_IMAGES:
Ben Kwa1c0a3892016-01-26 11:50:03 -0800790 return ROOT_IMAGES;
Steve McKay8659cbc2016-10-31 13:13:36 -0700791 case Providers.ROOT_ID_VIDEOS:
Ben Kwa1c0a3892016-01-26 11:50:03 -0800792 return ROOT_VIDEOS;
793 default:
794 return ROOT_OTHER;
795 }
Steve McKay8659cbc2016-10-31 13:13:36 -0700796 case Providers.AUTHORITY_STORAGE:
797 if (Providers.ROOT_ID_HOME.equals(DocumentsContract.getRootId(uri))) {
Ben Kwa1c0a3892016-01-26 11:50:03 -0800798 return ROOT_HOME;
799 } else {
800 return ROOT_DEVICE_STORAGE;
801 }
Steve McKay8659cbc2016-10-31 13:13:36 -0700802 case Providers.AUTHORITY_DOWNLOADS:
Ben Kwa1c0a3892016-01-26 11:50:03 -0800803 return ROOT_DOWNLOADS;
Steve McKay8659cbc2016-10-31 13:13:36 -0700804 case Providers.AUTHORITY_MTP:
Ben Kwaebaaea42016-01-28 18:15:07 -0800805 return ROOT_MTP;
Ben Kwa1c0a3892016-01-26 11:50:03 -0800806 default:
807 return ROOT_OTHER;
808 }
809 }
810
811 /** @see #sanitizeRoot(Uri) */
Ben Kwafaa27202016-01-28 16:39:57 -0800812 private static @Root int sanitizeRoot(RootInfo root) {
Ben Kwa1c0a3892016-01-26 11:50:03 -0800813 if (root.isRecents()) {
814 // Recents root is special and only identifiable via this method call. Other roots are
815 // identified by URI.
816 return ROOT_RECENTS;
817 } else {
818 return sanitizeRoot(root.getUri());
819 }
820 }
821
822 /** @see #sanitizeRoot(Uri) */
Ben Kwafaa27202016-01-28 16:39:57 -0800823 private static @Root int sanitizeRoot(ResolveInfo info) {
Ben Kwa1c0a3892016-01-26 11:50:03 -0800824 // Log all apps under a single bucket in the roots histogram.
825 return ROOT_THIRD_PARTY_APP;
826 }
827
828 /**
829 * Generates an int identifying a mime type. For privacy, this function only recognizes a small
830 * set of hard-coded types. For any other type, this function returns "other".
831 *
832 * @param mimeType
833 * @return
834 */
Ben Kwafaa27202016-01-28 16:39:57 -0800835 private static @Mime int sanitizeMime(String mimeType) {
Ben Kwa1c0a3892016-01-26 11:50:03 -0800836 if (mimeType == null) {
837 return MIME_NONE;
838 } else if ("*/*".equals(mimeType)) {
839 return MIME_ANY;
840 } else {
841 String type = mimeType.substring(0, mimeType.indexOf('/'));
842 switch (type) {
843 case "application":
844 return MIME_APPLICATION;
845 case "audio":
846 return MIME_AUDIO;
847 case "image":
848 return MIME_IMAGE;
849 case "message":
850 return MIME_MESSAGE;
851 case "multipart":
852 return MIME_MULTIPART;
853 case "text":
854 return MIME_TEXT;
855 case "video":
856 return MIME_VIDEO;
857 }
858 }
859 // Bucket all other types into one bucket.
860 return MIME_OTHER;
861 }
Ben Kwafaa27202016-01-28 16:39:57 -0800862
863 private static boolean isSystemProvider(String authority) {
864 switch (authority) {
Steve McKay8659cbc2016-10-31 13:13:36 -0700865 case Providers.AUTHORITY_MEDIA:
866 case Providers.AUTHORITY_STORAGE:
867 case Providers.AUTHORITY_DOWNLOADS:
Ben Kwafaa27202016-01-28 16:39:57 -0800868 return true;
869 default:
870 return false;
871 }
872 }
873
874 /**
875 * @param operation
876 * @param providerType
877 * @return An opcode, suitable for use as histogram bucket, for the given operation/provider
878 * combination.
879 */
880 private static @FileOp int getOpCode(@OpType int operation, @Provider int providerType) {
881 switch (operation) {
882 case FileOperationService.OPERATION_COPY:
883 switch (providerType) {
884 case PROVIDER_INTRA:
885 return FILEOP_COPY_INTRA_PROVIDER;
886 case PROVIDER_SYSTEM:
887 return FILEOP_COPY_SYSTEM_PROVIDER;
888 case PROVIDER_EXTERNAL:
889 return FILEOP_COPY_EXTERNAL_PROVIDER;
890 }
891 case FileOperationService.OPERATION_MOVE:
892 switch (providerType) {
893 case PROVIDER_INTRA:
894 return FILEOP_MOVE_INTRA_PROVIDER;
895 case PROVIDER_SYSTEM:
896 return FILEOP_MOVE_SYSTEM_PROVIDER;
897 case PROVIDER_EXTERNAL:
898 return FILEOP_MOVE_EXTERNAL_PROVIDER;
899 }
900 case FileOperationService.OPERATION_DELETE:
901 return FILEOP_DELETE;
902 default:
903 Log.w(TAG, "Unrecognized operation type when logging a file operation");
904 return FILEOP_OTHER;
905 }
906 }
907
908 /**
Ben Kwab41a5ed2016-02-17 16:06:22 -0800909 * Maps FileOperationService OpType values, to MetricsOpType values.
910 */
911 private static @MetricsOpType int toMetricsOpType(@OpType int operation) {
912 switch (operation) {
913 case FileOperationService.OPERATION_COPY:
914 return OPERATION_COPY;
915 case FileOperationService.OPERATION_MOVE:
916 return OPERATION_MOVE;
917 case FileOperationService.OPERATION_DELETE:
918 return OPERATION_DELETE;
919 case FileOperationService.OPERATION_UNKNOWN:
920 default:
921 return OPERATION_UNKNOWN;
922 }
923 }
924
925 private static @MetricsAction int toMetricsAction(int action) {
926 switch(action) {
927 case State.ACTION_OPEN:
928 return ACTION_OPEN;
929 case State.ACTION_CREATE:
930 return ACTION_CREATE;
931 case State.ACTION_GET_CONTENT:
932 return ACTION_GET_CONTENT;
933 case State.ACTION_OPEN_TREE:
934 return ACTION_OPEN_TREE;
Ben Kwab41a5ed2016-02-17 16:06:22 -0800935 case State.ACTION_BROWSE:
936 return ACTION_BROWSE;
937 case State.ACTION_PICK_COPY_DESTINATION:
938 return ACTION_PICK_COPY_DESTINATION;
939 default:
940 return ACTION_OTHER;
941 }
942 }
943
944 /**
Ben Kwafaa27202016-01-28 16:39:57 -0800945 * Count the given src documents and provide a tally of how many come from the same provider as
946 * the dst document (if a dst is provided), how many come from system providers, and how many
947 * come from external 3rd-party providers.
948 */
Steve McKay99f1dc32016-12-29 16:02:01 -0800949 private static void countProviders(
950 ProviderCounts counts, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) {
Ben Kwafaa27202016-01-28 16:39:57 -0800951 for (DocumentInfo doc: srcs) {
Steve McKay99f1dc32016-12-29 16:02:01 -0800952 countForAuthority(counts, doc.authority, dst);
Ben Kwafaa27202016-01-28 16:39:57 -0800953 }
Steve McKay99f1dc32016-12-29 16:02:01 -0800954 }
955
956 /**
957 * Count the given uris and provide a tally of how many come from the same provider as
958 * the dst document (if a dst is provided), how many come from system providers, and how many
959 * come from external 3rd-party providers.
960 */
961 private static void countProviders(ProviderCounts counts, List<Uri> uris) {
962 for (Uri uri: uris) {
963 countForAuthority(counts, uri.getAuthority(), null);
964 }
965 }
966
967 private static void countForAuthority(
968 ProviderCounts counts, String authority, @Nullable DocumentInfo dst) {
969 if (dst != null && authority.equals(dst.authority)) {
970 counts.intraProvider++;
971 } else if (isSystemProvider(authority)){
972 counts.systemProvider++;
973 } else {
974 counts.externalProvider++;
975 }
Ben Kwafaa27202016-01-28 16:39:57 -0800976 }
977
978 private static class ProviderCounts {
979 int intraProvider;
980 int systemProvider;
981 int externalProvider;
982 }
Ben Kwa1c0a3892016-01-26 11:50:03 -0800983}