Check if my application has usage access enabled

北战南征 提交于 2019-12-28 02:51:10

问题


I'm using the new UsageStatsManager API to get current foreground application in Android 5.0 Lollipop. In order to use this API, the user must enable the application in the Settings->Security->Apps with usage access screen.

I send the user directly to this screen with this Intent:


startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

Now, I want to validate the user enabled my application. I wanted to do so like I validate the user enabled my application to use the NotificationListenerService but I have no idea what is the String key, if it even exists.


Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
// Tried Settings.ACTION_USAGE_ACCESS_SETTINGS as key but it returns null

Second approach was to query the usage stats and check if it returns results (it returns an empty array when the app is not enabled) and it works most of the times but sometimes it returns 0 results even when my app is enabled.


UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService("usagestats");
long time = System.currentTimeMillis();
List stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);

if (stats == null || stats.isEmpty()) {
    // Usage access is not enabled
}

Is there a way to check if my application has usage access enabled?


回答1:


Received a great answer by someone on Twitter, tested working:

try {
   PackageManager packageManager = context.getPackageManager();
   ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
   AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
   int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
   return (mode == AppOpsManager.MODE_ALLOWED);

} catch (PackageManager.NameNotFoundException e) {
   return false;
}



回答2:


I previously used the same code as Bao Le, but I've run into the problem that certain devices (e.g. VF-895N) report usage stats as enabled even when they're not. As a workaround I've modified my code like this:

public static boolean hasPermission(@NonNull final Context context) {
    // Usage Stats is theoretically available on API v19+, but official/reliable support starts with API v21.
    if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) {
        return false;
    }

    final AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

    if (appOpsManager == null) {
        return false;
    }

    final int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.getPackageName());
    if (mode != AppOpsManager.MODE_ALLOWED) {
        return false;
    }

    // Verify that access is possible. Some devices "lie" and return MODE_ALLOWED even when it's not.
    final long now = System.currentTimeMillis();
    final UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
    final List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, now - 1000 * 10, now);
    return (stats != null && !stats.isEmpty());
}

Successfully tested on multiple devices.




回答3:


This is an alternative solutions:

AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
                    android.os.Process.myUid(), context.getPackageName());
return mode == AppOpsManager.MODE_ALLOWED;



回答4:


Here's my all-around solution for this (based on similar question and answer here) :

public static PermissionStatus getUsageStatsPermissionsStatus(Context context) {
    if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
        return PermissionStatus.CANNOT_BE_GRANTED;
    AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
    final int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.getPackageName());
    boolean granted = mode == AppOpsManager.MODE_DEFAULT ?
            (context.checkCallingOrSelfPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED)
            : (mode == AppOpsManager.MODE_ALLOWED);
    return granted ? PermissionStatus.GRANTED : PermissionStatus.DENIED;
}

public enum PermissionStatus {
    GRANTED, DENIED, CANNOT_BE_GRANTED
}



回答5:


Detecting when the usage access changes

Use this class to be notified when your app is granted or revoked usage access.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class UsagePermissionMonitor {

    private final Context context;
    private final AppOpsManager appOpsManager;
    private final Handler handler;
    private boolean isListening;
    private Boolean lastValue;

    public UsagePermissionMonitor(Context context) {
        this.context = context;
        appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        handler = new Handler();
    }

    public void startListening() {
        appOpsManager.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS, context.getPackageName(), usageOpListener);
        isListening = true;
    }

    public void stopListening() {
        lastValue = null;
        isListening = false;
        appOpsManager.stopWatchingMode(usageOpListener);
        handler.removeCallbacks(checkUsagePermission);
    }

    private final AppOpsManager.OnOpChangedListener usageOpListener = new AppOpsManager.OnOpChangedListener() {
        @Override
        public void onOpChanged(String op, String packageName) {
            // Android sometimes sets packageName to null
            if (packageName == null || context.getPackageName().equals(packageName)) {
                // Android actually notifies us of changes to ops other than the one we registered for, so filtering them out
                if (AppOpsManager.OPSTR_GET_USAGE_STATS.equals(op)) {
                    // We're not in main thread, so post to main thread queue
                    handler.post(checkUsagePermission);
                }
            }
        }
    };

    private final Runnable checkUsagePermission = new Runnable() {
        @Override
        public void run() {
            if (isListening) {
                int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), context.getPackageName());
                boolean enabled = mode == AppOpsManager.MODE_ALLOWED;

                // Each change to the permission results in two callbacks instead of one.
                // Filtering out the duplicates.
                if (lastValue == null || lastValue != enabled) {
                    lastValue = enabled;

                    // TODO: Do something with the result
                    Log.i(UsagePermissionMonitor.class.getSimpleName(), "Usage permission changed: " + enabled);
                }
            }
        }
    };

}

Credits

Based on code from epicality in another answer.




回答6:


This works down to KitKat (API 19)

    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;



回答7:


this code working in lollipop and marshmallow i used this code in my app

if (Build.VERSION.SDK_INT >= 21) {
            UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
            long time = System.currentTimeMillis();
            List stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);

            if (stats == null || stats.isEmpty()) {
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_USAGE_ACCESS_SETTINGS);
                context.startActivity(intent);
            }
    }



回答8:


If they are using an Amazon Fire tablet (and possibly other Fire OS devices) the user can download the application from a user installed Google Play Store then not have the option you want activated available in their OS. I know this because as a Fire OS user this happened to me a few minutes ago. Detecting whether a user has Fire OS and, if so, offering an option which actually exists would be fantastic for both user and dev.




回答9:


try this ,

public boolean check_UsgAccs(){
    long tme = System.currentTimeMillis();
    UsageStatsManager usm = (UsageStatsManager)getApplicationContext().getSystemService(Context.USAGE_STATS_SERVICE);
    List<UsageStats> al= usm.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, tme - (1000 * 1000), tme);
        return  al.size()>0;

    }


来源:https://stackoverflow.com/questions/27215013/check-if-my-application-has-usage-access-enabled

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!