前言
Android5.0以前,使用ActivityManager的getRunningTasks()方法,可以得到应用包名和Activity;Android5.0以后,可以通过UsageStatsManager.queryUsageStats方法替代,但是也只能得到应用包名。当然你也可以通过AccessibilityService,也可以得到应用包名和Activity。正好最近用到UsageStatsManager来实现获取顶部应用的功能,写篇文章系统的学习一下。
相关知识
在介绍UsageStatsManager之前,先学习一下相关联的一些知识。
UsageStats
UsageStats是在指定时间区间内某个应用使用统计数据的封装类。包含的公开方法及对应的作用如下:
方法 | 用途 |
---|---|
getFirstTimeStamp() | 获取指定时间区间内应用第一次使用时间戳 |
getLastTimeStamp() | 获取指定时间区间内应用最后一次使用时间戳 |
getLastTimeUsed() | 获取应用最后一次使用时间戳 |
getPackageName() | 获取应用包名 |
getTotalTimeInForeground() | 获取应用在前台的时间 |
EventStats
EventStats是在指定时间区间内某个类型事件统计数据的封装类。包含的公开方法及对应的作用如下:
方法 | 用途 |
---|---|
getCount() | 获取在指定时间区间内事件发生的次数 |
getEventType() | 获取事件类型 |
getFirstTimeStamp() | 获取指定时间区间内这个事件第一次发生的时间戳 |
getLastEventTime() | 获取这个事件最后一次发生的时间戳 |
getLastTimeStamp() | 获取指定时间区间内这个事件最后一次发生的时间戳 |
getTotalTime() | 获取这个事件总共发生的次数 |
UsageEvents
UsageEvents是用来返回指定时间区间内组件状态变化事件数据的封装类,其返回的组件状态变化事件类型如下:
UsageEvents.Event:
public static final int NONE = 0;
public static final int MOVE_TO_FOREGROUND = 1;
public static final int MOVE_TO_BACKGROUND = 2;
public static final int END_OF_DAY = 3;
public static final int CONTINUE_PREVIOUS_DAY = 4;
public static final int CONFIGURATION_CHANGE = 5;
public static final int SYSTEM_INTERACTION = 6;
public static final int USER_INTERACTION = 7;
public static final int SHORTCUT_INVOCATION = 8;
public static final int CHOOSER_ACTION = 9;
public static final int NOTIFICATION_SEEN = 10;
public static final int STANDBY_BUCKET_CHANGED = 11;
public static final int NOTIFICATION_INTERRUPTION = 12;
public static final int SLICE_PINNED_PRIV = 13;
public static final int SLICE_PINNED = 14;
public static final int SCREEN_INTERACTIVE = 15;
public static final int SCREEN_NON_INTERACTIVE = 16;
public static final int KEYGUARD_SHOWN = 17;
public static final int KEYGUARD_HIDDEN = 18;
UsageStatsManager
UsageStatsManager 是Android提供统计应用使用情况的服务。通过这个服务可以获取指定时间区间内应用使用统计数据、组件状态变化事件统计数据以及硬件配置信息统计数据。提供的主要查询方法如下表:
方法 | 用途 |
---|---|
queryAndAggregateUsageStats(long beginTime, long endTime) | 获取指定时间区间内使用统计数据,以应用包名为键值进行数据合并。 |
queryConfigurations(int intervalType, long beginTime, long endTime) | 获取指定时间区间内硬件配置信息统计数据。 |
queryEventStats(int intervalType, long beginTime, long endTime) | 获取指定时间区间内发生组件状态变化事件统计数据。 |
queryEvents(long beginTime, long endTime) | 获取指定时间区间内组件状态变化事件 |
queryEventsForSelf(long beginTime, long endTime) | 与queryEvents相似,获取指定时间区间内本应用的组件状态变化事件 |
queryUsageStats(int intervalType, long beginTime, long endTime) | 获取指定时间区间内应用使用统计数据。 |
查询时间间隔如下:
public static final int INTERVAL_DAILY = 0;
public static final int INTERVAL_WEEKLY = 1;
public static final int INTERVAL_MONTHLY = 2;
public static final int INTERVAL_YEARLY = 3;
public static final int INTERVAL_BEST = 4;
除了上述查询方法,UsageStatsManager还提供了一些其他的重要方法。
方法 | 用途 |
---|---|
isAppInactive(String packageName) | 判断应用是否处于活跃状态 |
setAppInactive(String packageName, boolean inactive) | 设置应用活跃状态,系统API |
registerAppUsageObserver(int observerId, @NonNull String[] packages, long timeLimit,@NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) | 注册应用使用观察者,系统API |
unregisterAppUsageObserver(int observerId) | 注销应用使用观察者,系统API |
获取顶部应用示例
使用步骤如下:
1、在AndroidManifest.xml中声明权限。
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
2、启动授权设置界面
public static void checkUsageStateAccessPermission(Context context) {
if(!AppUsageUtil.checkAppUsagePermission(context)) {
AppUsageUtil.requestAppUsagePermission(context);
}
}
public static boolean checkAppUsagePermission(Context context) {
UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
if(usageStatsManager == null) {
return false;
}
long currentTime = System.currentTimeMillis();
// try to get app usage state in last 1 min
List<UsageStats> stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - 60 * 1000, currentTime);
if (stats.size() == 0) {
return false;
}
return true;
}
public static void requestAppUsagePermission(Context context) {
Intent intent = new Intent(android.provider.Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.i(TAG,"Start usage access settings activity fail!");
}
}
3、查询10秒钟前应用使用统计数据并根据最后使用时间进行排序,得到的最后使用的应用。
public static String getTopActivityPackageName(@NonNull Context context) {
final UsageStatsManager usageStatsManager = (UsageStatsManager)context.getSystemService(Context.USAGE_STATS_SERVICE);
if(usageStatsManager == null) {
return PACKAGE_NAME_UNKNOWN;
}
String topActivityPackageName = PACKAGE_NAME_UNKNOWN;
long time = System.currentTimeMillis();
// 查询最后十秒钟使用应用统计数据
List<UsageStats> usageStatsList = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*10, time);
// 以最后使用时间为标准进行排序
if(usageStatsList != null) {
SortedMap<Long,UsageStats> sortedMap = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : usageStatsList) {
sortedMap.put(usageStats.getLastTimeUsed(),usageStats);
}
if(sortedMap.size() != 0) {
topActivityPackageName = sortedMap.get(sortedMap.lastKey()).getPackageName();
Log.d(TAG,"Top activity package name = " + topActivityPackageName);
}
}
return topActivityPackageName;
}
dump命令
adb shell dumpsys usagestats
小结
本文基于Android9.0 SDK列举了应用使用数据统计服务UsageStatsManager所能提供的服务,并给出获取顶部应用的代码示例。其他获取前台应用的方法可以参看《4种获取前台应用的方法(肯定有你不知道的)》,里面关于UsageStatsManager使用的相关优化可以学习一下。