Merge "Created metric events for scoped directory access API." into nyc-dev
am: c50bf8e33e
* commit 'c50bf8e33e67c26b5dc4fd18ec665d2985fd42e7':
Created metric events for scoped directory access API.
This commit is contained in:
@@ -507,7 +507,7 @@ public class Environment {
|
||||
* </ul>
|
||||
* @hide
|
||||
*/
|
||||
private static final String[] STANDARD_DIRECTORIES = {
|
||||
public static final String[] STANDARD_DIRECTORIES = {
|
||||
DIRECTORY_MUSIC,
|
||||
DIRECTORY_PODCASTS,
|
||||
DIRECTORY_RINGTONES,
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import static android.os.Environment.STANDARD_DIRECTORIES;
|
||||
import static com.android.documentsui.Shared.DEBUG;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringDef;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
@@ -32,6 +34,7 @@ import com.android.documentsui.model.RootInfo;
|
||||
import com.android.documentsui.services.FileOperationService;
|
||||
import com.android.documentsui.services.FileOperationService.OpType;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -376,6 +379,84 @@ public final class Metrics {
|
||||
logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
|
||||
}
|
||||
|
||||
// Types for logInvalidScopedAccessRequest
|
||||
public static final String SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS =
|
||||
"scoped_directory_access_invalid_args";
|
||||
public static final String SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY =
|
||||
"scoped_directory_access_invalid_dir";
|
||||
public static final String SCOPED_DIRECTORY_ACCESS_ERROR =
|
||||
"scoped_directory_access_error";
|
||||
|
||||
@StringDef(value = {
|
||||
SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS,
|
||||
SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY,
|
||||
SCOPED_DIRECTORY_ACCESS_ERROR
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface InvalidScopedAccess{}
|
||||
|
||||
public static void logInvalidScopedAccessRequest(Context context,
|
||||
@InvalidScopedAccess String type) {
|
||||
MetricsLogger.count(context, type, 1);
|
||||
switch (type) {
|
||||
case SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS:
|
||||
case SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY:
|
||||
case SCOPED_DIRECTORY_ACCESS_ERROR:
|
||||
MetricsLogger.count(context, type, 1);
|
||||
break;
|
||||
default:
|
||||
Log.wtf(TAG, "invalid InvalidScopedAccess: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
// Types for logValidScopedAccessRequest
|
||||
public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED = 0;
|
||||
public static final int SCOPED_DIRECTORY_ACCESS_GRANTED = 1;
|
||||
public static final int SCOPED_DIRECTORY_ACCESS_DENIED = 2;
|
||||
|
||||
@IntDef(flag = true, value = {
|
||||
SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED,
|
||||
SCOPED_DIRECTORY_ACCESS_GRANTED,
|
||||
SCOPED_DIRECTORY_ACCESS_DENIED
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ScopedAccessGrant {}
|
||||
|
||||
public static void logValidScopedAccessRequest(Activity activity, String directory,
|
||||
@ScopedAccessGrant int type) {
|
||||
int index = -1;
|
||||
for (int i = 0; i < STANDARD_DIRECTORIES.length; i++) {
|
||||
if (STANDARD_DIRECTORIES[i].equals(directory)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
final String packageName = activity.getCallingPackage();
|
||||
switch (type) {
|
||||
case SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED:
|
||||
MetricsLogger.action(activity,
|
||||
MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE,
|
||||
packageName);
|
||||
MetricsLogger.action(activity,
|
||||
MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER, index);
|
||||
break;
|
||||
case SCOPED_DIRECTORY_ACCESS_GRANTED:
|
||||
MetricsLogger.action(activity,
|
||||
MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE, packageName);
|
||||
MetricsLogger.action(activity,
|
||||
MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER, index);
|
||||
break;
|
||||
case SCOPED_DIRECTORY_ACCESS_DENIED:
|
||||
MetricsLogger.action(activity,
|
||||
MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE, packageName);
|
||||
MetricsLogger.action(activity,
|
||||
MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER, index);
|
||||
break;
|
||||
default:
|
||||
Log.wtf(TAG, "invalid ScopedAccessGrant: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
|
||||
*
|
||||
|
||||
@@ -17,9 +17,18 @@
|
||||
package com.android.documentsui;
|
||||
|
||||
import static android.os.Environment.isStandardDirectory;
|
||||
import static android.os.Environment.STANDARD_DIRECTORIES;
|
||||
import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
|
||||
import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
|
||||
import static com.android.documentsui.Shared.DEBUG;
|
||||
import static com.android.documentsui.Metrics.logInvalidScopedAccessRequest;
|
||||
import static com.android.documentsui.Metrics.logValidScopedAccessRequest;
|
||||
import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED;
|
||||
import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_DENIED;
|
||||
import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ERROR;
|
||||
import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_GRANTED;
|
||||
import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS;
|
||||
import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
@@ -73,6 +82,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null) {
|
||||
if (DEBUG) Log.d(TAG, "missing intent");
|
||||
logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return;
|
||||
@@ -82,12 +92,14 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
|
||||
+ storageVolume);
|
||||
logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
final String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME);
|
||||
if (directoryName == null) {
|
||||
logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
|
||||
if (DEBUG) Log.d(TAG, "missing extra " + EXTRA_DIRECTORY_NAME + " on " + intent);
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
@@ -125,6 +137,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
|
||||
+ " and directory " + directoryName);
|
||||
logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
|
||||
return false;
|
||||
}
|
||||
final StorageManager sm =
|
||||
@@ -138,6 +151,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
|
||||
+ file.getAbsolutePath() + "')");
|
||||
logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -159,6 +173,8 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
// Checks if the user has granted the permission already.
|
||||
final Intent intent = getIntentForExistingPermission(activity, file);
|
||||
if (intent != null) {
|
||||
logValidScopedAccessRequest(activity, directory,
|
||||
SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED);
|
||||
activity.setResult(RESULT_OK, intent);
|
||||
activity.finish();
|
||||
return true;
|
||||
@@ -166,12 +182,14 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
|
||||
if (volumeLabel == null) {
|
||||
Log.e(TAG, "Could not get volume for " + file);
|
||||
logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gets the package label.
|
||||
final String appLabel = getAppLabel(activity);
|
||||
if (appLabel == null) {
|
||||
// Error already logged.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -198,6 +216,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
try {
|
||||
return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
|
||||
} catch (NameNotFoundException e) {
|
||||
logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
|
||||
Log.w(TAG, "Could not get label for package " + packageName);
|
||||
return null;
|
||||
}
|
||||
@@ -217,18 +236,21 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
return volume.isVisibleForWrite(userId) && root.equals(path);
|
||||
}
|
||||
|
||||
private static Uri getGrantedUriPermission(ContentProviderClient provider, File file) {
|
||||
private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
|
||||
File file) {
|
||||
// Calls ExternalStorageProvider to get the doc id for the file
|
||||
final Bundle bundle;
|
||||
try {
|
||||
bundle = provider.call("getDocIdForFileCreateNewDir", file.getPath(), null);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Did not get doc id from External Storage provider for " + file, e);
|
||||
logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
|
||||
return null;
|
||||
}
|
||||
final String docId = bundle == null ? null : bundle.getString("DOC_ID");
|
||||
if (docId == null) {
|
||||
Log.e(TAG, "Did not get doc id from External Storage provider for " + file);
|
||||
logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
|
||||
return null;
|
||||
}
|
||||
Log.d(TAG, "doc id for " + file + ": " + docId);
|
||||
@@ -242,9 +264,9 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
return uri;
|
||||
}
|
||||
|
||||
private static Intent createGrantedUriPermissionsIntent(ContentProviderClient provider,
|
||||
File file) {
|
||||
final Uri uri = getGrantedUriPermission(provider, file);
|
||||
private static Intent createGrantedUriPermissionsIntent(Context context,
|
||||
ContentProviderClient provider, File file) {
|
||||
final Uri uri = getGrantedUriPermission(context, provider, file);
|
||||
return createGrantedUriPermissionsIntent(uri);
|
||||
}
|
||||
|
||||
@@ -261,7 +283,8 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
private static Intent getIntentForExistingPermission(OpenExternalDirectoryActivity activity,
|
||||
File file) {
|
||||
final String packageName = activity.getCallingPackage();
|
||||
final Uri grantedUri = getGrantedUriPermission(activity.getExternalStorageClient(), file);
|
||||
final Uri grantedUri =
|
||||
getGrantedUriPermission(activity, activity.getExternalStorageClient(), file);
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "checking if " + packageName + " already has permission for " + grantedUri);
|
||||
final ActivityManager am =
|
||||
@@ -298,7 +321,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final String folder = mFile.getName();
|
||||
final String directory = mFile.getName();
|
||||
final Activity activity = getActivity();
|
||||
final OnClickListener listener = new OnClickListener() {
|
||||
|
||||
@@ -306,12 +329,16 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = null;
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
intent = createGrantedUriPermissionsIntent(
|
||||
intent = createGrantedUriPermissionsIntent(mActivity,
|
||||
mActivity.getExternalStorageClient(), mFile);
|
||||
}
|
||||
if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
|
||||
logValidScopedAccessRequest(activity, directory,
|
||||
SCOPED_DIRECTORY_ACCESS_DENIED);
|
||||
activity.setResult(RESULT_CANCELED);
|
||||
} else {
|
||||
logValidScopedAccessRequest(activity, directory,
|
||||
SCOPED_DIRECTORY_ACCESS_GRANTED);
|
||||
activity.setResult(RESULT_OK, intent);
|
||||
}
|
||||
activity.finish();
|
||||
@@ -320,7 +347,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
|
||||
final CharSequence message = TextUtils
|
||||
.expandTemplate(
|
||||
getText(R.string.open_external_dialog_request), mAppLabel, folder,
|
||||
getText(R.string.open_external_dialog_request), mAppLabel, directory,
|
||||
mVolumeLabel);
|
||||
return new AlertDialog.Builder(activity, R.style.AlertDialogTheme)
|
||||
.setMessage(message)
|
||||
@@ -333,6 +360,7 @@ public class OpenExternalDirectoryActivity extends Activity {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
super.onCancel(dialog);
|
||||
final Activity activity = getActivity();
|
||||
logValidScopedAccessRequest(activity, mFile.getName(), SCOPED_DIRECTORY_ACCESS_DENIED);
|
||||
activity.setResult(RESULT_CANCELED);
|
||||
activity.finish();
|
||||
}
|
||||
|
||||
@@ -478,5 +478,30 @@ message MetricsEvent {
|
||||
// Logged when we execute an app transition. This indicates the device uptime in seconds when
|
||||
// the transition was executed.
|
||||
APP_TRANSITION_DEVICE_UPTIME_SECONDS = 325;
|
||||
|
||||
// User granted access to the request folder; action takes an integer
|
||||
// representing the folder's index on Environment.STANDARD_DIRECTORIES
|
||||
ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER = 326;
|
||||
|
||||
// User denied access to the request folder; action takes an integer
|
||||
// representing the folder's index on Environment.STANDARD_DIRECTORIES
|
||||
ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER = 327;
|
||||
|
||||
// User granted access to the request folder; action pass package name
|
||||
// of calling package.
|
||||
ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE = 328;
|
||||
|
||||
// User denied access to the request folder; action pass package name
|
||||
// of calling package.
|
||||
ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE = 329;
|
||||
|
||||
// App requested access to a directory it has already been granted
|
||||
// access before; action takes an integer representing the folder's
|
||||
// index on Environment.STANDARD_DIRECTORIES
|
||||
ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER = 330;
|
||||
|
||||
// App requested access to a directory it has already been granted
|
||||
// access before; action pass package name of calling package.
|
||||
ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE = 331;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user