(Android 9.0)应用使用数据统计服务——UsageStatsManager

前言

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

Demo

小结

本文基于Android9.0 SDK列举了应用使用数据统计服务UsageStatsManager所能提供的服务,并给出获取顶部应用的代码示例。其他获取前台应用的方法可以参看《4种获取前台应用的方法(肯定有你不知道的)》,里面关于UsageStatsManager使用的相关优化可以学习一下。

    原文作者:peter_RD_nj
    原文地址: https://www.jianshu.com/p/3b6bcf9cec67
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞