Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
180 views
in Technique[技术] by (71.8m points)

How to check if "android.permission.PACKAGE_USAGE_STATS" permission is given?

Background

I'm trying to get app-launched statistics, and on Lollipop it's possible by using the UsageStatsManager class, as such (original post here):

manifest:

<uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions"/>

opening the activity that will let the user confirm giving you this permission:

startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

getting the stats, aggregated :

 private static final String USAGE_STATS_SERVICE ="usagestats"; // Context.USAGE_STATS_SERVICE);
 ...
 final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService(USAGE_STATS_SERVICE);
 final Map<String,UsageStats> queryUsageStats=usageStatsManager.queryAndAggregateUsageStats(fromTime,toTime);

The problem

I can't seem to check if the permission that you need ("android.permission.PACKAGE_USAGE_STATS") is granted. All I've tried so far always returns that it is denied.

The code works, but the permission check doesn't work well.

What I've tried

you can check for a permission being granted using either this:

String permission = "android.permission.PACKAGE_USAGE_STATS";
boolean granted=getContext().checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;   

or this:

String permission = "android.permission.PACKAGE_USAGE_STATS";
boolean granted=getPackageManager().checkPermission(permission,getPackageName())== PackageManager.PERMISSION_GRANTED;   

Both always returned that it got denied (even when I've granted the permission as a user).

Looking at the code of UsageStatsManager, I've tried to come up with this workaround:

      UsageStatsManager usm=(UsageStatsManager)getSystemService("usagestats");
      Calendar calendar=Calendar.getInstance();
      long toTime=calendar.getTimeInMillis();
      calendar.add(Calendar.YEAR,-1);
      long fromTime=calendar.getTimeInMillis();
      final List<UsageStats> queryUsageStats=usm.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,fromTime,toTime);
      boolean granted=queryUsageStats!=null&&queryUsageStats!=Collections.EMPTY_LIST;

It worked, but it's still a workaround.

The question

How come I don't get the correct result of the permission check?

What should be done to check it better?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Special permissions that are granted by the user in the system settings (usage stats access, notification access, …) are handled by AppOpsManager, which was added in Android 4.4.

Note that besides user granting you access in the system settings you typically need a permission in the Android manifest (or some component), without that your app doesn't even show in the system settings. For usage stats you need android.permission.PACKAGE_USAGE_STATS permission.

There's not much documentation about that but you can always check Android sources for it. The solution might seem bit hacky because some constants were added later to the AppOpsManager, and some constants (e.g. for checking different permissions) are still hidden in private APIs.

AppOpsManager appOps = (AppOpsManager) context
        .getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow("android:get_usage_stats", 
        android.os.Process.myUid(), context.getPackageName());
boolean granted = mode == AppOpsManager.MODE_ALLOWED;

This tells you if the permission was granted by the user. Note that since API level 21 there is constant AppOpsManager.OPSTR_GET_USAGE_STATS = "android:get_usage_stats".

I tested this check on Lollipop (including 5.1.1) and it works as expected. It tells me whether the user gave the explicit permission without any crash. There's also method appOps.checkOp() which might throw a SecurityException.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...