Как получить последние задания на Android "L"?

Фон

Мое приложение позволяет сортировать список приложений к моменту их недавнего запуска.

Проблема

Начиная с Android "L", функция getRecentTasks вернет список приложений, которые было запущено в текущем приложении, как написано в документации:

Если ваше приложение использует ActivityManager.getRecentTasks()...

С введением новых параллельных документов и мероприятий задач в предстоящей версии (см. Параллельные документы и в разделе "Реценты" ниже), Метод ActivityManager.getRecentTasks() теперь устарел для улучшения конфиденциальность пользователей. Для обратной совместимости этот метод все еще возвращает небольшое подмножество его данных, включая собственные вызывающие приложения задачи и, возможно, некоторые другие не чувствительные задачи (например, Home). Если ваше приложение использует этот метод для извлечения собственных задач, использования android.app.ActivityManager.getAppTasks() вместо этого, чтобы получить это информация.

То же самое написано при использовании ADT, чтобы показать документацию по этой функции (недоступной в настоящее время в Интернете):

Этот метод устарел. Начиная с L, этот метод больше не доступен сторонним приложениям: как внедрение документально-ориентированного recents означает, что он может передавать личную информацию вызывающему абоненту. Для обратной совместимости, он все равно вернет небольшое подмножество своих данные: по крайней мере, собственные задачи вызывающего абонента (хотя см. getAppTasks() для правильный поддерживаемый способ получения этой информации) и, возможно, некоторые другие задачи, такие как дома, которые, как известно, не чувствительны.

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

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

Что я пробовал

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

Я мог бы также использовать значение важности процессов и, возможно, значение важностиReasonComponent, но это всего лишь эвристика и догадки...

Вопрос

Есть ли способ преодолеть это ограничение? Любое обходное решение, о котором я не думал?

Возможно ли это с помощью root? Или BusyBox?

Ответ 1

Чтобы получить имя вершины (Foreground) в настоящее время, вам нужно использовать API статистики использования в Android Lollipop.

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

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);

Получить верхнее имя пакета:

String topPackageName ;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
    UsageStatsManager mUsageStatsManager = (UsageStatsManager)getSystemService("usagestats");                       
    long time = System.currentTimeMillis(); 
    // We get usage stats for the last 10 seconds
    List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*10, time);                                    
    // Sort the stats by the last time used
    if(stats != null) {
        SortedMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
        for (UsageStats usageStats : stats) {
            mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
        }                    
        if(!mySortedMap.isEmpty()) {
            topPackageName =  mySortedMap.get(mySortedMap.lastKey()).getPackageName();                                   
        }                                       
    }
}

Ответ 2

Если вы используете UsageStats для получения текущего пакета переднего плана, вы получите неправильную информацию, когда пользователь открывает ящик уведомлений или на заблокированном экране. (протестировано на Android Lollipop и Marshmallow)

Вы должны использовать UsageStatsManager.queryEvents() и искать последнее событие с типом события MOVE_TO_FOREGROUND для определения текущего пакета переднего плана.

Ответ 3

@user3742392 ответ хороший, однако использование TreeMap для поиска последнего используемого времени - это немного переборщик (особенно если вы хотите периодически проверять приложение сверху).

Вот отредактированный ответ без TreeMap с простым циклом:

String topPackageName;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService("usagestats");
    long currentTime = System.currentTimeMillis();
    // get usage stats for the last 10 seconds
    List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - 1000 * 10, currentTime);
    // search for app with most recent last used time
    if (stats != null) {
        long lastUsedAppTime = 0;
        for (UsageStats usageStats : stats) {
            if (usageStats.getLastTimeUsed() > lastUsedAppTime) {
                topPackageName = usageStats.getPackageName();
                lastUsedAppTime = usageStats.getLastTimeUsed();
            }
        }
    }
}

Ответ 4

Lollipop не рекомендовал метод; однако есть новый API, который позволяет просматривать использование приложения. Метод был устаревшим из-за проблем с безопасностью.:\

UsageStatsManager имеет несколько полезных методов для просмотра активности между интервалом времени. Надеюсь, этого достаточно для ваших нужд!

https://developer.android.com/reference/android/app/usage/package-summary.html