Android

Android已安装应用使用时长统计-UsageStatsMan

2020-06-17  本文已影响0人  丨逐风者丨

先看效果图

应用使用时长统计截图

源码地址

https://github.com/ZengCS/ZengDemoAlbum

Step1 授权

<uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions" />
public static boolean hasAppUsagePermission(Context context) {
    UsageStatsManager usageStatsManager = null;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
        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 2 min
    List<UsageStats> stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - 2 * 60 * 1000, currentTime);
    return JListKit.isNotEmpty(stats);
}
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!");
    }
}

Step2 根据获取APP使用情况列表

private void getAppUsage(long beginTime, long endTime) {
    String fmt = "yyyy-MM-dd HH:mm:ss";
    mHolder.tvTimeRange.setText(String.format("(%s - %s)",
            JDateKit.timeToDate(fmt, beginTime),
            JDateKit.timeToDate(fmt, endTime)));
    // setTitle("数据分析中...");
    showLoading("数据分析中...");

    // a task can be executed only once,init is required every time
    mLoadAppUsageTask = new LoadAppUsageTask(beginTime, endTime, list -> {
        mItems = list;
        initAdapter();
    });
    mLoadAppUsageTask.execute();
}
/**
 * Created by ZengCS on 2019/5/30.
 * E-mail:zengcs@vip.qq.com
 * Add:成都市天府软件园E3
 * 加载应用使用情况 Task
 */
public class LoadAppUsageTask extends AsyncTask<Void, Void, ArrayList<AppUsageBean>> {
    private static final String TAG = "LoadAppUsageTask";
    private Callback mCallback;
    private long beginTime, endTime;

    public LoadAppUsageTask(long beginTime, long endTime, Callback mCallback) {
        this.beginTime = beginTime;
        this.endTime = endTime;
        this.mCallback = mCallback;
        mPackageManager = BaseApplication.getApplication().getPackageManager();
    }

    // 方法1:onPreExecute()
    // 作用:执行 线程任务前的操作
    @Override
    protected void onPreExecute() {
        // 执行前显示提示
        Log.d(TAG, "********** 开始获取应用使用情况 **********");
    }

    // 方法2:doInBackground()
    // 作用:接收输入参数、执行任务中的耗时操作、返回 线程任务执行的结果
    // 此处通过计算从而模拟“加载进度”的情况

    @Override
    protected ArrayList<AppUsageBean> doInBackground(Void... voids) {
        return readAppUsageList();
    }

    private ArrayList<AppUsageBean> readAppUsageList() {
        ArrayList<AppUsageBean> mItems = JListKit.newArrayList();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            UsageStatsManager usage = (UsageStatsManager) BaseApplication.getApplication().getSystemService(Context.USAGE_STATS_SERVICE);
            if (usage == null) return mItems;

            // 查询并按包名进行聚合操作
            Map<String, UsageStats> statsMap = usage.queryAndAggregateUsageStats(beginTime, endTime);
            Set<String> keySet = statsMap.keySet();
            for (String packageName : keySet) {
                UsageStats usageStats = statsMap.get(packageName);
                if (usageStats == null) continue;
                long totalTimeInForeground = usageStats.getTotalTimeInForeground();
                if (totalTimeInForeground <= 0) continue;// 小于1秒的都按照没有打开过处理

                AppUsageBean appUsageBean = new AppUsageBean(packageName, usageStats);
                ApplicationInfo info = getAppInfo(packageName);
                appUsageBean.setAppInfo(info);
                if (info != null) {
                    // 获取应用名称
                    String label = (String) info.loadLabel(mPackageManager);
                    Drawable icon = info.loadIcon(mPackageManager);
                    appUsageBean.setAppName(label);
                    appUsageBean.setAppIcon(icon);
                } else {
                    appUsageBean.setAppName("应用已卸载");
                    // Log.e(TAG, "已经找不到包名为[" + packageName + "]的应用");
                }

                mItems.add(appUsageBean);
                // 打印日志
                if (BuildConfig.DEBUG) {
                    Log.d("UsageStats", "**********************************************");
                    Log.d("UsageStats", packageName);
                    // Log.d("UsageStats", "运行时长:" + JDateKit.timeToStringChineChinese(totalTimeInForeground));
                    Log.d("UsageStats", String.format("运行时长:%s (%sms)", JDateKit.timeToStringChineChinese(totalTimeInForeground), totalTimeInForeground));
                    String fmt = "yyyy-MM-dd HH:mm:ss.SSS";
                    Log.d("UsageStats", "开始启动:" + JDateKit.timeToDate(fmt, usageStats.getFirstTimeStamp()));
                    Log.d("UsageStats", "最后启动:" + JDateKit.timeToDate(fmt, usageStats.getLastTimeStamp()));
                    Log.d("UsageStats", "最近使用:" + JDateKit.timeToDate(fmt, usageStats.getLastTimeUsed()));
                }
            }
        }
        return mItems;
    }

    private PackageManager mPackageManager;

    private ApplicationInfo getAppInfo(String pkgName) {
        try {
            // ApplicationInfo info = mPackageManager.getApplicationInfo(pkgName, PackageManager.GET_ACTIVITIES);
            return mPackageManager.getApplicationInfo(pkgName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            // e.printStackTrace();
            Log.e(TAG, "已经找不到包名为[" + pkgName + "]的应用");
        }
        return null;
    }

    // 方法3:onPostExecute()
    // 作用:接收线程任务执行结果、将执行结果显示到UI组件
    @Override
    protected void onPostExecute(ArrayList<AppUsageBean> list) {
        Log.d(TAG, "共获取到[" + list.size() + "]个系统应用。");
        if (mCallback != null)
            mCallback.onPostExecute(list);
    }

    public interface Callback {
        void onPostExecute(ArrayList<AppUsageBean> list);
    }
}

Step3 根据packageName获取APP的图标和名称

ApplicationInfo info = getAppInfo(packageName);
if (info != null) {
    // 获取应用名称
    String label = (String) info.loadLabel(mPackageManager);
    Drawable icon = info.loadIcon(mPackageManager);
    appUsageBean.setAppName(label);
    appUsageBean.setAppIcon(icon);
} else {
    appUsageBean.setAppName("应用已卸载");
    // Log.e(TAG, "已经找不到包名为[" + packageName + "]的应用");
}

private ApplicationInfo getAppInfo(String pkgName) {
    try {
        // ApplicationInfo info = mPackageManager.getApplicationInfo(pkgName, PackageManager.GET_ACTIVITIES);
        return mPackageManager.getApplicationInfo(pkgName, 0);
    } catch (PackageManager.NameNotFoundException e) {
        // e.printStackTrace();
        Log.e(TAG, "已经找不到包名为[" + pkgName + "]的应用");
    }
    return null;
}

Step4 设置统计规则(多种)

/**
 * @return 今日零点的时间
 */
private long getTodayTime0() {
    // 获取今天凌晨0点0分0秒的time
    Calendar calendar = Calendar.getInstance();
    calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH),
            0, 0, 0);
    return calendar.getTimeInMillis();
}
public void onTabClick(int position) {
    Log.d(TAG, "onTabClick() called with: position = [" + position + "]");

    setTitle(TAB_NAMES[position]);
    long currTime = System.currentTimeMillis();

    switch (position) {
        case 0:// 今天的数据  00:00 到 现在
            getAppUsage(getTodayTime0(), currTime);
            break;
        case 1:// 昨天的数据  昨天00:00 - 今天00:00
            long todayTime0 = getTodayTime0();
            getAppUsage(todayTime0 - DateUtils.DAY_IN_MILLIS, todayTime0);
            break;
        case 2:// 最近7天数据
            getAppUsage(currTime - DateUtils.WEEK_IN_MILLIS, currTime);
            break;
        case 3:// 最近30天数据
            getAppUsage(currTime - DateUtils.DAY_IN_MILLIS * 30, currTime);
            break;
        case 4:// 最近一年的数据
            getAppUsage(currTime - DateUtils.DAY_IN_MILLIS * 365, currTime);
            break;
    }
}

Step5 将数据展示在RecyclerView

private long maxTime;// 当前列表中 使用最久的APP时间 用于计算进度条百分比

private void initAdapter() {
    if (JListKit.isNotEmpty(mItems)) {
        Collections.sort(mItems);// 按使用时长排序
        maxTime = mItems.get(0).getTotalTimeInForeground();
    } else {
        maxTime = 1;
    }
    setTitle(String.format("%s (共%s条)", getTitle(), mItems.size()));
    if (mAdapter == null) {
        String fmt = "yyyy-MM-dd HH:mm:ss";
        mAdapter = new CommonRecyclerAdapter<AppUsageBean>(R.layout.item_app_usage, mItems) {
            @Override
            protected void convert(@NonNull BaseViewHolder helper, AppUsageBean item) {
                helper.setText(R.id.id_tv_app_name, String.format("%s(%s)", item.getAppName(), item.getPackageName()));
                Drawable appIcon = item.getAppIcon();
                if (appIcon != null) {
                    helper.setImageDrawable(R.id.id_iv_app_icon, appIcon);
                } else {
                    helper.setImageResource(R.id.id_iv_app_icon, R.mipmap.ic_launcher);
                }
                long totalTimeInForeground = item.getTotalTimeInForeground();
                helper.setText(R.id.id_tv_time_in_foreground, String.format("使用时长:%s (%sms)", JDateKit.timeToStringChineChinese(totalTimeInForeground), totalTimeInForeground));
                helper.setText(R.id.id_tv_last_usage, String.format("上次使用:%s", JDateKit.timeToDate(fmt, item.getLastTimeUsed())));
                // 计算进度条百分比
                float percent = (float) item.getTotalTimeInForeground() / maxTime;
                Guideline guideline = helper.getView(R.id.guideline);
                guideline.setGuidelinePercent(percent);
            }
        };
        mHolder.rvAppUsage.setAdapter(mAdapter);
        mHolder.rvAppUsage.setLayoutManager(new LinearLayoutManager(this));
    } else {
        mAdapter.setNewInstance(mItems);
    }
    hideLoading();
}

源码地址

https://github.com/ZengCS/ZengDemoAlbum

上一篇 下一篇

猜你喜欢

热点阅读