Как закрыть ACTION_USAGE_ACCESS_SETTINGS, когда пользователь нажимает правильное целевое приложение?

Я использую Intent ACTION_USAGE_ACCESS_SETTINGS в настройке (Settings->Security->Apps with usage access) для использования UsageStatsManager в версии Lollipop.

 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);
            }

Во-первых, onCreate() проверяет разрешение для приложения. и включите намерение, если приложение не имеет разрешения (не проверяет)

@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;
    }
}

Мой вопрос в том, что я хочу закрыть окно настроек, если пользователь выбирает (проверять) в целевом приложении, в противном случае он покажет сообщение о имени приложения для указания выбранного пользователя. Как мне это сделать? Спасибо. Я думаю, что это будет делать в onActivityResult function

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS){
        ...
    }
}

Я ссылаюсь на ссылку Проверить, включено ли у моего приложения доступ к использованию, но он просто проверяет разрешение приложения.

Ответ 1

AppOpsManager имеет еще один интересный метод:

void startWatchingMode (String op, String packageName, AppOpsManager.OnOpChangedListener callback)

из документации:

Мониторинг изменений в рабочем режиме для данного операционного процесса в данном пакете приложений.

В основном это то, что вы ожидаете → реагировать на разрешение на чтение изменений в использовании статистики использования пакетов.

Что вам нужно сделать, это проверить состояние надбавки, а если оно не предоставлено, откройте "Настройки" и создайте прослушиватель:

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);
}

Будьте осторожны и удалите слушателя, вызывающего метод:

void stopWatchingMode (AppOpsManager.OnOpChangedListener callback)

Приведенный выше пример просто открывает основную деятельность приложения. Однако вы можете добавить любое поведение:

  • передать параметр дополнительного намерения, чтобы сообщить только что открытую активность, чтобы показать диалог пользователю
  • Запустите фоновый сервис, чтобы показать тост, этот пользователь должен предоставить разрешение.
  • и т.д...

Отметьте этот репозиторий, поскольку он демонстрирует этот случай и общее использование NetworkStats.