Как использовать UsageStatsManager?

Фон

Google отвергла функцию " getRecentTasks" класса ActivityManager. Теперь все, что нужно сделать, - это получить список приложений, которые открыло текущее приложение.

Я даже написал сообщение об этом qaru.site/info/30242/..., но я заметил, что это невозможно.

Проблема

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

Класс называется "UsageStatsManager", и я предполагаю, что функция " queryUsageStats "выполняет эту работу.

Кроме того, похоже, что у него есть новое разрешение ( "android.permission.PACKAGE_USAGE_STATS" ), которое является системным разрешением, но оно написано, что:

Объявление разрешения подразумевает намерение использовать API и пользователя устройства может предоставить разрешение через приложение "Настройки".

Вот еще одна ссылка об этой новой функциональности.

Что я нашел

Я просмотрел код Android и заметил, что "Контекст" имеет USAGE_STATS_SERVICE, который в JavaDocs говорит следующее:

/**
 * Use with {@link #getSystemService} to retrieve a {@link
 * android.app.UsageStatsManager} for interacting with the status bar.
 *
 * @see #getSystemService
 * @see android.app.UsageStatsManager
 * @hide
 */
public static final String USAGE_STATS_SERVICE = "usagestats";

Странно, что не только он говорит "status bar", но и имя пакета не совпадает (должно быть "android.app.usage.UsageStatsManager" ).

Я также добавил правильное разрешение:

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

и здесь код, который я использую:

  final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService("usagestats");// Context.USAGE_STATS_SERVICE);
  final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
  final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);

В самом эмуляторе я пошел в " Settings"->"security"->"apps with usage access" и включил мое приложение.

Однако при запуске кода все, что я получаю, это пустой список...

Вопрос

Как вы используете UsageStatsManager?

Кроме того, как вы разрешаете пользователю предоставлять разрешение самым простым способом? Или это автоматически делается, как только приложение пытается получить необходимую информацию?

Что происходит при попытке использовать этот класс, пока пользователь еще не подтвердил его?

Как я могу заставить код вернуть мне реальный список приложений?

Ответ 1

Я думаю, что документация была просто короткой для материала календаря. Я не думаю, что на самом деле он работает только с 2014 года; однако я могу ошибаться.

Чтобы получить доступ к фактическому списку UsageStats, вам нужно будет создать объект Calendar с правильным месяцем, днем ​​и годом. Точно как MRK сказал в другом ответе. Я скопировал и исправил ошибки в коде MRK, чтобы каждый, кто видит это в будущем, мог видеть это.

Calendar beginCal = Calendar.getInstance();
beginCal.set(Calendar.DATE, 1);
beginCal.set(Calendar.MONTH, 0);
beginCal.set(Calendar.YEAR, 2012);

Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.DATE, 1);
endCal.set(Calendar.MONTH, 0);
endCal.set(Calendar.YEAR, 2014);

final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginCal.getTimeInMillis(), endCal.getTimeInMillis());

-Credit MRK; исправлено мной (он случайно просто положил cal вместо beginCal и endCal)

Ниже приведен код настроек доступа к использованию.:)

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);

Ответ 3

Отвечая на ваш последний вопрос "Как я могу заставить код вернуть мне реальный список приложений?". queryUsageStats принимает время начала и окончания в миллисекундах, а не значение года в int.

Calendar beginCal = Calendar.getInstance();
beginCal.set(Calendar.DATE, 1);
beginCal.set(Calendar.MONTH, 0);
beginCal.set(Calendar.YEAR, 2012);

Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.DATE, 1);
endCal.set(Calendar.MONTH, 0);
endCal.set(Calendar.YEAR, 2014);

final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginCal.getTimeInMillis(), endCal.getTimeInMillis());

Это должно вернуть список UsageStats для 2012 и 2013 годов (помните, что время окончания не ограничивается диапазоном конечных результатов).

Ответ 4

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

Ответ 5

На самом деле есть приложение включенное в примерный код AOSP: developers/samples/android/system/AppUsageStatistics/

Он включает в себя все биты, необходимые для использования UsageStats в приложении:

Подводя итог и применим к вашему примеру:

  • Кажется, вы правильно запросили разрешения и получили разрешения на доступ к статистике использования.
  • Вы правильно получаете системную службу UsageStats.
  • Однако период запроса, который вы запрашиваете, является коротким: Аргументы beginTime и endTime измеряются в миллисекундах с эпохи. Calendar экземпляры могут дать вам это значение с помощью getTimeinMillis(). То, что вы ошибочно делаете, - это указать только цифры года (2015 и 2017, если вы запустите программу сегодня). Эти значения интерпретируются как миллисекунды с эпохи, и, следовательно, интервал составляет всего 2 миллисекунды, а в 1970 году это время.

Вместо следующего фрагмента кода, который вы опубликовали, скопируйте приведенный ниже пример:

Неправильно:

final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);

Правильно:

final long currentTime = System.currentTimeMillis(); // Get current time in milliseconds

final Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -2); // Set year to beginning of desired period.
final long beginTime = cal.getTimeInMillis(); // Get begin time in milliseconds

final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginTime, currentTime);

Ответ 6

вы можете сделать это

//noinspection ResourceType
final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService("usagestats");// Context.USAGE_STATS_SERVICE);
final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);