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?
Things like Digital Wellbeing, Device Health Services, Google Play Services, and other stock apps should be left alone to ensure proper functionality, but most third-party apps can safely be disabled here. To do so, select the app from this list, then tap the toggle switch next to "Permit usage access."
Open Settings and tap Apps & notifications. Tap Permission manager to open the Android permission controller app. Click a specific permission from the app permissions list that you're interested in, like location. Here you'll see apps that have access to your location all the time or only while in use.
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; }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With