Android 5.1.1 и выше – getRunningAppProcesses () возвращает только мой пакет приложений

Кажется, Google наконец закрыл все двери для получения текущего пакета приложений переднего плана.

После обновления Lollipop, который убил getRunningTasks(int maxNum) и благодаря этому ответу , я использовал этот код для получения пакета приложений переднего плана с Lollipop:

 final int PROCESS_STATE_TOP = 2; RunningAppProcessInfo currentInfo = null; Field field = null; try { field = RunningAppProcessInfo.class.getDeclaredField("processState"); } catch (Exception ignored) { } ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); List appList = am.getRunningAppProcesses(); for (RunningAppProcessInfo app : appList) { if (app.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && app.importanceReasonCode == 0 ) { Integer state = null; try { state = field.getInt( app ); } catch (Exception ignored) { } if (state != null && state == PROCESS_STATE_TOP) { currentInfo = app; break; } } } return currentInfo; 

Android 5.1.1 и выше (6.0 Marshmallow), похоже, также убил getRunningAppProcesses() . Теперь он возвращает список вашего собственного пакета приложений.


UsageStatsManager

Мы можем использовать новый API UsageStatsManager как описано здесь, но он не работает для всех приложений. Некоторые системные приложения возвратят тот же пакет

 com.google.android.googlequicksearchbox 

AccessibilityService (декабрь 2017 года: запрет на использование компанией Google)

В некоторых приложениях используется AccessibilityService (как показано здесь ), но у него есть некоторые недостатки.


Есть ли другой способ получить текущий пакет приложений?

Чтобы получить список запущенных процессов на Android 1.6 – Android 6.0, вы можете использовать эту библиотеку, которую я написал: https://github.com/jaredrummler/AndroidProcesses . Библиотека читает / proc, чтобы получить информацию о процессе.

Google значительно ограничил доступ к / proc в Android Nougat. Чтобы получить список запущенных процессов на Android Nougat, вам нужно будет использовать UsageStatsManager или получить root-доступ.

Нажмите историю изменений для предыдущих альтернативных решений.

  private String printForegroundTask() { String currentApp = "NULL"; if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats"); long time = System.currentTimeMillis(); List appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); if (appList != null && appList.size() > 0) { SortedMap mySortedMap = new TreeMap(); for (UsageStats usageStats : appList) { mySortedMap.put(usageStats.getLastTimeUsed(), usageStats); } if (mySortedMap != null && !mySortedMap.isEmpty()) { currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName(); } } } else { ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE); List tasks = am.getRunningAppProcesses(); currentApp = tasks.get(0).processName; } Log.e("adapter", "Current App in foreground is: " + currentApp); return currentApp; } 

Используйте этот метод для получения задачи переднего плана. U потребуется системное разрешение “android: get_usage_stats”

 public static boolean needPermissionForBlocking(Context context){ 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 true; } } 

Если пользователь включил это в настройке -> Security-> app с доступом к использованию. После этого вы получите переднюю задачу. Подобный процесс Чистый matser от Cheetahamobile google play link

Взгляните на https://github.com/ricvalerio/foregroundappchecker , это может быть то, что вам нужно. Предоставляет пример кода и устраняет боль при использовании кросс-версии детектора переднего плана.

Вот два примера:

 AppChecker appChecker = new AppChecker(); String packageName = appChecker.getForegroundApp(); 

Или регулярно проверяйте:

 AppChecker appChecker = new AppChecker(); appChecker .when("com.other.app", new AppChecker.Listener() { @Override public void onForeground(String packageName) { // do something } ) .when("com.my.app", new AppChecker.Listener() { @Override public void onForeground(String packageName) { // do something } ) .other(new AppChecker.Listener() { @Override public void onForeground(String packageName) { // do something } ) .timeout(1000) .start(this); 

Google ограничил эту функциональность только для системных приложений. Как сообщалось в биг-бите , вам потребуется разрешение REAL_GET_TASKS для доступа туда.

Теперь приложения должны иметь … permission.REAL_GET_TASKS, чтобы иметь возможность получать информацию о процессах для всех приложений. Только информация о процессе для вызывающего приложения будет возвращена, если приложение не имеет разрешения. Привилегии приложений временно смогут получать информацию о процессах для всех приложений, если у них нет нового разрешения, но устарели … permission.GET_TASKS Кроме того, только системные приложения могут получить разрешение REAL_GET_TASKS.

 public class AccessibilityDetectingService extends AccessibilityService { @Override protected void onServiceConnected() { super.onServiceConnected(); //Configure these here for compatibility with API 13 and below. AccessibilityServiceInfo config = new AccessibilityServiceInfo(); config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; if (Build.VERSION.SDK_INT >= 16) //Just in case this helps config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; setServiceInfo(config); } @Override public void onAccessibilityEvent(final AccessibilityEvent event) { if (event == null ) { return; } else if(event.getPackageName() == null && event.getClassName() == null){ return; } if (activityInfo != null){ Log.d("CurrentActivity", componentName.flattenToShortString()); } } private ActivityInfo tryGetActivity(ComponentName componentName) { try { return getPackageManager().getActivityInfo(componentName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } } @Override public void onInterrupt() { } } }//`enter code here`uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />  

Затем запустите службу и доступ к приложениям в настройках вашего устройства -> доступность -> Приложение в этой службе.

Просто выкидывая потенциальную оптимизацию к тому, что я себе представляю, это сильно скопированный в скопированном виде код для обнаружения самого верхнего приложения на Android M.

Эта

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats"); long time = System.currentTimeMillis(); List appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time); if (appList != null && appList.size() > 0) { SortedMap mySortedMap = new TreeMap(); for (UsageStats usageStats : appList) { mySortedMap.put(usageStats.getLastTimeUsed(), usageStats); } if (mySortedMap != null && !mySortedMap.isEmpty()) { currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName(); } } } 

Может быть упрощено для этого

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { UsageStatsManager usm = (UsageStatsManager) context.getSystemService( Context.USAGE_STATS_SERVICE); long time = System.currentTimeMillis(); List appStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time); if (appStatsList != null && !appStatsList.isEmpty()) { currentApp = Collections.max(appStatsList, (o1, o2) -> Long.compare(o1.getLastTimeUsed(), o2.getLastTimeUsed())).getPackageName(); } } 

Я обнаружил, что использую этот код в 2-секундном цикле и задаюсь вопросом, почему я использовал сложное решение, которое было O (n * log (n)), когда более простое решение было доступно в Collections.max (), которое является O (n ).

Попробуйте использовать getRunningServices() вместо метода getRunningAppProcesses() .

  ActivityManager mActivityManager = (ActivityManager) getSy stemService(Context.ACTIVITY_SERVICE); List appProcessInfoList = mActivityManager.getRunningServices(Integer.MAX_VALUE); 
  • как отображать извлеченные данные json в listview с использованием baseadapter
  • Запуск Skype из программы Programmatically & Pass Number - Android
  • Динамическое обновление адаптера AutoCompleteTextView
  • Объяснение близости задачи Android
  • Webview загружает html из каталога ресурсов
  • Открытый файл PDF для Android
  • Нарисуйте прозрачный круг за пределами
  • Android Fragment onAttach () устарел
  • разница между версиями подписей - V1 (подпись Jar) и V2 (полная подпись APK) при создании подписанного apk в AndroidStudio?
  • Android - Как передать HashMap между действиями?
  • Как resize текста заголовка в панели действий?
  • Давайте будем гением компьютера.