Pertanyaan Bagaimana cara memeriksa apakah izin "android.permission.PACKAGE_USAGE_STATS" diberikan?


Latar Belakang

Saya mencoba untuk mendapatkan statistik yang diluncurkan aplikasi, dan pada Lollipop itu mungkin dengan menggunakan UsageStatsManager kelas, seperti itu (posting asli sini):

nyata:

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

membuka aktivitas yang memungkinkan pengguna mengkonfirmasi memberi Anda izin ini:

startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

mendapatkan statistik, dikumpulkan:

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

Masalah

Saya tidak dapat memeriksa apakah izin yang Anda perlukan ("android.permission.PACKAGE_USAGE_STATS") diberikan. Semua yang saya coba sejauh ini selalu mengembalikan bahwa itu ditolak.

Kode berfungsi, tetapi pemeriksaan izin tidak berfungsi dengan baik.

Apa yang sudah saya coba

Anda dapat memeriksa izin yang diberikan menggunakan ini:

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

atau ini:

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

Keduanya selalu kembali karena ditolak (bahkan ketika saya sudah memberikan izin sebagai pengguna).

Melihat kode UsageStatsManager, saya sudah mencoba untuk mendapatkan solusi ini:

      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;

Ini berhasil, tetapi masih merupakan solusi.

Pertanyaan

Kenapa saya tidak mendapatkan hasil yang benar dari cek izin?

Apa yang harus dilakukan untuk memeriksanya lebih baik?


32
2018-03-07 23:05


asal


Jawaban:


Dengan penyelidikan kami: jika MODE adalah default (MODE_DEFAULT), pemeriksaan izin ekstra diperlukan. Terima kasih atas usaha pemeriksaan Weien.

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

if (mode == AppOpsManager.MODE_DEFAULT) {
    granted = (context.checkCallingOrSelfPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED);
} else {
    granted = (mode == AppOpsManager.MODE_ALLOWED);
}

11
2018-02-22 11:51



Izin khusus yang diberikan oleh pengguna dalam pengaturan sistem (akses statistik penggunaan, akses notifikasi, ...) ditangani oleh AppOpsManager, yang ditambahkan di Android 4.4.

Perhatikan bahwa selain pengguna yang memberi Anda akses dalam pengaturan sistem, Anda biasanya memerlukan izin di manifes Android (atau beberapa komponen), tanpa itu aplikasi Anda bahkan tidak muncul di pengaturan sistem. Untuk statistik penggunaan yang Anda butuhkan android.permission.PACKAGE_USAGE_STATS izin.

Tidak banyak dokumentasi tentang itu tetapi Anda selalu dapat memeriksa sumber Android untuk itu. Solusinya mungkin tampak sedikit hacky karena beberapa konstanta ditambahkan kemudian ke AppOpsManager, dan beberapa konstanta (misalnya untuk memeriksa izin yang berbeda) masih tersembunyi di API pribadi.

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;

Ini memberitahu Anda jika izin itu diberikan oleh pengguna. Perhatikan bahwa karena API level 21 ada konstan AppOpsManager.OPSTR_GET_USAGE_STATS = "android:get_usage_stats".

Saya menguji cek ini pada Lollipop (termasuk 5.1.1) dan berfungsi seperti yang diharapkan. Ini memberitahu saya apakah pengguna memberikan izin eksplisit tanpa kecelakaan. Ada juga metode appOps.checkOp() yang mungkin melempar a SecurityException.


24
2018-03-08 00:04



Argumen kedua dari checkOpNoThrow aku s uidtidak pid.

Mengubah kode untuk mencerminkan yang tampaknya memperbaiki masalah yang dialami orang lain:

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;

4
2017-08-18 14:03