I am using Intent ACTION_USAGE_ACCESS_SETTINGS
in setting (Settings->Security->Apps with usage access
) to use UsageStatsManager
in the Lollipop version.
public static final int MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS = 1;
if(!hasPermission()){
startActivityForResult(
new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS),
MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS);
}
First, onCreate() will check the permission for the app. and turn on the Intent if the app has no permission (does not check)
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private boolean hasPermission() {
try {
PackageManager packageManager = getApplicationContext().getPackageManager();
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(getApplicationContext().getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) getApplicationContext().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;
}
}
My question is that I want to close the setting window, if the user chooses (check) in target app, otherwise, it will show a message about application name to guide the chosen of the user. How can I do it? Thank you. I think it will do in onActivityResult
function
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS){
...
}
}
I refer the link Check if my application has usage access enabled, but it just checks enable of the app.
AppOpsManager
has another interesting method:
void startWatchingMode (String op, String packageName, AppOpsManager.OnOpChangedListener callback)
from documentation:
Monitor for changes to the operating mode for the given op in the given app package.
Basically this is what you expect -> react on permission to read package usage stats switch change.
What you need to do is check the allowance state and if it is not granted, open the Settings and create a listener:
private boolean hasPermissionToReadNetworkHistory() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
final AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
if (mode == AppOpsManager.MODE_ALLOWED) {
return true;
}
appOps.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS,
getApplicationContext().getPackageName(),
new AppOpsManager.OnOpChangedListener() {
@Override
@TargetApi(Build.VERSION_CODES.KITKAT)
public void onOpChanged(String op, String packageName) {
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
if (mode != AppOpsManager.MODE_ALLOWED) {
return;
}
appOps.stopWatchingMode(this);
Intent intent = new Intent(MainActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
}
});
requestReadNetworkHistoryAccess();
return false;
}
private void requestReadNetworkHistoryAccess() {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
}
Be careful and remove the listener calling the method:
void stopWatchingMode (AppOpsManager.OnOpChangedListener callback)
The example above is just opening main application activity. However you might add any behaviour:
- pass extra intent parameter to inform just opened activity to show dialog to user
- Start background service to show toast, that user must grant the permission.
- etc...
Check out this repository, as it demonstrates this case and the overall usage of NetworkStats
.