新しいUsageStatsManager
APIを使用して 現在のフォアグラウンドアプリケーションを取得 in Android 5.0 Lollipop。このAPIを使用するには、ユーザーがSettings->Security->Apps with usage access
画面のアプリケーション。
このインテントを使用して、ユーザーをこの画面に直接送ります。
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
次に、ユーザーがアプリケーションを有効にしたことを確認します。ユーザーがアプリケーションでNotificationListenerService
を使用できるようにしたことを確認したいのですが、存在する場合でも、文字列キーが何であるかわかりません。
Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
// Tried Settings.ACTION_USAGE_ACCESS_SETTINGS as key but it returns null
2番目のアプローチは、使用統計をクエリし、結果が返されるかどうかを確認することでした(アプリが有効でない場合は空の配列を返します)。ほとんどの場合機能しますが、アプリが有効でも、0の結果を返す場合があります。
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
}
アプリケーションで使用状況アクセスが有効になっているかどうかを確認する方法はありますか?
動作確認済みのTwitterで誰かから素晴らしい回答を受け取りました:
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;
}
以前はBao Leと同じコードを使用していましたが、特定のデバイス(VF-895Nなど)が使用統計を有効にしていない場合でも、有効であると報告するという問題に遭遇しました。回避策として、次のようにコードを変更しました。
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());
}
複数のデバイスでのテストに成功しました。
これは代替ソリューションです。
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;
これに対する私の総合的な解決策があります(同様の質問と回答に基づいています 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
}
このクラスを使用して、アプリに使用権のアクセスが許可または取り消されたときに通知します。
@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);
}
}
}
};
}
これは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;