End

UsageStatsManager 使用统计

本文地址


目录

UsageStatsManager 使用总结

UsageStatsManager

参考文章1
参考文章2
参考文章3

Provides access to device usage history and statistics. Usage data is aggregated into 汇总成 time intervals 时间间隔: days, weeks, months, and years.

A request for data in the middle of a time interval 间隔 will include that interval.

NOTE: Most methods on this API require the permission android.permission.PACKAGE_USAGE_STATS. However, declaring 声明 the permission implies 暗示 intention 意图 to use the API and the user of the device still needs to grant permission through the Settings application. Methods which only return the information for the calling package do not require this permission. E.g. getAppStandbyBucket() and queryEventsForSelf().

应用使用统计信息

查询应用使用统计信息,包括:应用的前台使用时长,应用首次启动的时间,应用启动次数,应用最近一次使用的时间等

queryUsageStats

List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime)

Gets application usage stats for the given time range, aggregated by the specified interval.

The returned list will contain one or more UsageStats objects for each package, with usage data that covers at least the given time range 至少覆盖给定的时间范围.

Note: The begin and end times of the time range may be expanded to the nearest whole interval period.

queryAndAggregateUsageStats

Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime)

A convenience method that queries for all stats in the given range, merges the resulting data, and keys it by package name.

其实就是逐个遍历 queryUsageStats 返回的结果,按照包名进行整合,得出多条记录的合并结果后再封装起来。

UsageStats

UsageStats

Contains usage statistics for an app package for a specific time range.

常用方法:

  • long getFirstTimeStamp():Get the beginning of the time range this UsageStats represents, measured in milliseconds since the epoch纪元. 获取此UsageStats表示的时间范围的开始。
  • long getLastTimeStamp():Get the end of the time range this UsageStats represents, ...
  • long getLastTimeUsed():Get the last time this package's activity was used, ...
  • long getTotalTimeInForeground():Get the total time this package spent in the foreground, ...

API 29 新增方法:

  • long getLastTimeVisible():Get the last time this package's activity is visible in the UI, ...
  • long getLastTimeForegroundServiceUsed():Get the last time this package's foreground service was used, ...
  • long getTotalTimeVisible():Get the total time this package's activity is visible in the UI, ...
  • long getTotalTimeForegroundServiceUsed():Get the total time this package's foreground services are started, ...

时间间隔类型

  • UsageStatsManager.INTERVAL_DAILY :天存储级别的数据
  • UsageStatsManager.INTERVAL_WEEKLY :星期存储级别的数据
  • UsageStatsManager.INTERVAL_MONTHLY :月存储级别的数据
  • UsageStatsManager.INTERVAL_YEARLY :年存储级别的数据
  • UsageStatsManager.INTERVAL_BEST :根据给定时间范围选取最佳时间间隔类型

测试

测试代码

private void testUsageStats(@NonNull Context context) {
    long endTime = System.currentTimeMillis();
    long beginTime = endTime - 1000 * 60 * 60 * 24 * 3; //最近3天
    UsageStatsManager manager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
    List<UsageStats> usageStatsList = manager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, beginTime, endTime);
    for (UsageStats usageStats : usageStatsList) {
        printUsageStatsInfo(usageStats);
    }
    
    System.out.println("--------------------------------------------------------------------------");
    Map<String, UsageStats> map = manager.queryAndAggregateUsageStats(beginTime, endTime);
    for (Map.Entry<String, UsageStats> entry : map.entrySet()) {
        printUsageStatsInfo(entry.getValue());
    }
}
private void printUsageStatsInfo(UsageStats usageStats) {
    DateFormat format = new SimpleDateFormat("yyyy.MM.dd_HH:mm:ss", Locale.getDefault());
    
    String packageName = usageStats.getPackageName();
    String beginningTime = format.format(new Date(usageStats.getFirstTimeStamp()));
    String endTime = format.format(new Date(usageStats.getLastTimeStamp()));
    String lastUsedTime = format.format(new Date(usageStats.getLastTimeUsed())); //上次使用时间
    long foregroundTime = usageStats.getTotalTimeInForeground() / 1000; //前台总共运行的时间
    
    int appLaunchCount = 0; //应用被拉起启动次数
    int launchCount = 0;//应用前台启动次数(包括自己启动其他activity)
    try {
        appLaunchCount = (int) usageStats.getClass().getDeclaredMethod("getAppLaunchCount").invoke(usageStats);
        launchCount = usageStats.getClass().getDeclaredField("mLaunchCount").getInt(usageStats);
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    if (packageName.equals("com.tencent.mm") || packageName.equals("com.xiaomi.smarthome") || packageName.equals("com.eg.android.AlipayGphone")) {
        Log.i("bqt", "| " + packageName + " | " + beginningTime + " | " + endTime + " | " + lastUsedTime + " | " + foregroundTime + " | " + appLaunchCount + " | " + launchCount + " |");
    }
}

测试结果一

使用 UsageStatsManager.INTERVAL_BEST 的结果

表一:queryUsageStats

| packageName | beginningTime | endTime | lastUsedTime | 前台时长 | 拉起次数 | 切换次数 |
| :------------: | :------------: |
| com.tencent.mm | 2020.11.16_12:46:02 | 2020.11.20_00:13:56 | 2020.11.20_00:13:56 | 9890 | 96 | 68 |
| com.eg.android.AlipayGphone | 2020.11.16_12:46:02 | 2020.11.20_00:12:13 | 2020.11.18_13:06:54 | 27 | 3 | 0 |

表二:queryAndAggregateUsageStats

| packageName | beginningTime | endTime | lastUsedTime | 前台时长 | 拉起次数 | 切换次数 |
| :------------: | :------------: |
| com.tencent.mm | 2020.11.16_12:46:02 | 2020.11.20_00:13:56 | 2020.11.20_00:13:56 | 9890 | 96 | 68 |
| com.eg.android.AlipayGphone | 2020.11.16_12:46:02 | 2020.11.20_00:12:13 | 2020.11.18_13:06:54 | 27 | 3 | 0 |

使用 UsageStatsManager.INTERVAL_DAILY 的结果

表一:queryUsageStats

| packageName | beginningTime | endTime | lastUsedTime | 前台时长 | 拉起次数 | 切换次数 |
| :------------: | :------------: |
| com.tencent.mm | 2020.11.16_12:46:02 | 2020.11.17_12:46:02 | 2020.11.17_12:17:00 | 2930 | 33 | 0 |
| com.eg.android.AlipayGphone | 2020.11.16_12:46:02 | 2020.11.17_12:46:02 | 1970.01.01_07:59:57 | 0 | 0 | 0 |
| com.tencent.mm | 2020.11.17_12:46:38 | 2020.11.18_12:46:38 | 2020.11.18_12:46:33 | 2575 | 25 | 0 |
| com.eg.android.AlipayGphone | 2020.11.17_12:46:38 | 2020.11.18_12:46:38 | 2020.11.17_22:01:34 | 7 | 2 | 0 |
| com.tencent.mm | 2020.11.18_12:46:48 | 2020.11.19_12:46:48 | 2020.11.19_12:46:48 | 2113 | 21 | 0 |
| com.eg.android.AlipayGphone | 2020.11.18_12:46:48 | 2020.11.19_12:46:48 | 2020.11.18_13:06:54 | 19 | 1 | 0 |
| com.tencent.mm | 2020.11.19_12:46:55 | 2020.11.20_00:13:56 | 2020.11.20_00:13:56 | 2270 | 17 | 68 |

表二:queryAndAggregateUsageStats

| packageName | beginningTime | endTime | lastUsedTime | 前台时长 | 拉起次数 | 切换次数 |
| :------------: | :------------: |
| com.tencent.mm | 2020.11.16_12:46:02 | 2020.11.20_00:13:56 | 2020.11.20_00:13:56 | 9890 | 96 | 68 |
| com.eg.android.AlipayGphone | 2020.11.16_12:46:02 | 2020.11.20_00:12:13 | 2020.11.18_13:06:54 | 27 | 3 | 0 |

测试结果二

表一:queryUsageStats

| packageName | beginningTime | endTime | lastUsedTime | 前台时长 | 拉起次数 | 切换次数 |
| :------------: | :------------: |
| com.tencent.mm | 2020.11.08_12:35:24 | 2020.11.09_12:35:24 | 2020.11.09_12:05:16 | 2000 | 19 | 0 |
| com.eg.android.AlipayGphone | 2020.11.08_12:35:24 | 2020.11.09_12:35:24 | 2020.11.09_11:43:58 | 17 | 4 | 0 |
| com.tencent.mm | 2020.11.09_12:36:01 | 2020.11.10_12:36:01 | 2020.11.10_10:12:31 | 3119 | 39 | 0 |
| com.xiaomi.smarthome | 2020.11.09_12:36:01 | 2020.11.10_12:36:01 | 2020.11.10_12:36:01 | 489 | 4 | 0 |
| com.eg.android.AlipayGphone | 2020.11.09_12:36:01 | 2020.11.10_12:36:01 | 2020.11.10_09:09:22 | 115 | 12 | 0 |
| com.tencent.mm | 2020.11.10_12:36:03 | 2020.11.11_12:36:03 | 2020.11.11_11:24:53 | 5374 | 65 | 0 |
| com.xiaomi.smarthome | 2020.11.10_12:36:03 | 2020.11.11_12:36:03 | 2020.11.10_21:46:02 | 5109 | 13 | 0 |
| com.eg.android.AlipayGphone | 2020.11.10_12:36:03 | 2020.11.11_12:36:03 | 2020.11.10_18:15:47 | 583 | 2 | 0 |
| com.tencent.mm | 2020.11.11_12:37:05 | 2020.11.12_01:16:07 | 2020.11.11_23:00:43 | 1009 | 24 | 81 |
| com.xiaomi.smarthome | 2020.11.11_12:37:05 | 2020.11.12_01:22:28 | 2020.11.12_01:22:28 | 53 | 4 | 23 |
| com.eg.android.AlipayGphone | 2020.11.11_12:37:05 | 2020.11.12_01:16:07 | 2020.11.11_22:29:44 | 9 | 2 | 4 |

表二:queryAndAggregateUsageStats

| packageName | beginningTime | endTime | lastUsedTime | 前台时长 | 拉起次数 | 切换次数 |
| :------------: | :------------: |
| com.tencent.mm | 2020.11.08_12:35:24 | 2020.11.12_01:16:07 | 2020.11.11_23:00:43 | 11503 | 147 | 81 |
| com.xiaomi.smarthome | 2020.11.09_12:36:01 | 2020.11.12_01:22:28 | 2020.11.12_01:22:28 | 5652 | 21 | 23 |
| com.eg.android.AlipayGphone | 2020.11.08_12:35:24 | 2020.11.12_01:16:07 | 2020.11.11_22:29:44 | 725 | 20 | 4 |

设备状态事件统计

事件包括:锁屏事件、切换前台事件、切换到后台事件、屏幕交互状态事件、屏幕非交互状态事件等

queryEventStats

List<EventStats> queryEventStats(int intervalType, long beginTime, long endTime) //API 28添加

Gets aggregated 汇总 event stats for the given time range, aggregated by the specified interval.

The returned list will contain a EventStats object for each event type that is being aggregated and has data for an interval that is a subset of the time range given.

返回的列表将为每个正在汇总的事件类型包含一个EventStats对象,并具有间隔时间的数据,该间隔是给定时间范围的子集。

EventStats

EventStats

Contains usage statistics for an event type for a specific time range.

常用方法:

  • void add(EventStats right):Add the statistics from the right EventStats to the left. The event type for both UsageStats objects must be the same. 系统服务调用的方法
  • int getCount():Return the number of times that this event occurred over the interval.
  • int getEventType():Return the type of event this is usage for. May be one of the event constants in UsageEvents.Event.
  • long getFirstTimeStamp():Get the beginning of the time range this EventStats represents, measured in milliseconds since the epoch.
  • long getLastEventTime():Get the last time this event triggered, measured in milliseconds since the epoch.
  • long getLastTimeStamp():Get the end of the time range this EventStats represents, measured in milliseconds since the epoch.
  • long getTotalTime():Get the total time this event was active, measured in milliseconds.

涉及到的四种事件

  • UsageEvents.Event.SCREEN_INTERACTIVE = 15:交互状态。An event type denoting 表示 that the screen has gone in to an interactive 交互 state (turned on for full user interaction, not ambient display 环境显示 or other non-interactive state). 表示屏幕已进入交互状态的事件类型(为完全用户交互而打开,而不是环境显示或其他非交互状态)
  • UsageEvents.Event.SCREEN_NON_INTERACTIVE = 16:非交互状态。An event type denoting that the screen has gone in to a non-interactive state (completely turned off or turned on only in a non-interactive state like ambient display). 表示屏幕已进入非交互状态的事件类型(完全关闭或仅在非交互状态(如环境显示)中完全打开)。
  • UsageEvents.Event.KEYGUARD_SHOWN = 17:锁屏。An event type denoting that the screen's keyguard 键盘锁 has been shown, whether or not the screen is off.指示屏幕的键盘锁已经显示,无论屏幕是否关闭。
  • UsageEvents.Event.KEYGUARD_HIDDEN = 18:解锁。An event type denoting that the screen's keyguard has been hidden. This typically happens when the user unlocks their phone after turning it on. 表示屏幕的键盘锁已隐藏。 当用户在打开手机后解锁手机时,通常会发生这种情况。

测试代码

private void testEventStats(@NonNull Context context) {
    long endTime = System.currentTimeMillis();
    long beginTime = endTime - 1000 * 60 * 60 * 24 * 3; //最近3天
    UsageStatsManager manager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
    List<EventStats> usageStatsList = manager.queryEventStats(UsageStatsManager.INTERVAL_BEST, beginTime, endTime);
    
    for (EventStats eventStats : usageStatsList) {
        printEventStatsInfo(eventStats);
    }
}
private void printEventStatsInfo(EventStats eventStats) {
    DateFormat format = new SimpleDateFormat("yyyy.MM.dd_HH:mm:ss", Locale.getDefault());
    
    int count = eventStats.getCount();
    int eventType = eventStats.getEventType();
    String beginningTime = format.format(new Date(eventStats.getFirstTimeStamp()));
    String endTime = format.format(new Date(eventStats.getLastTimeStamp()));
    String lastEventTime = format.format(new Date(eventStats.getLastEventTime()));
    long totalTime = eventStats.getTotalTime() / 1000;
    
    Log.i("bqt", "| " + count + " | " + eventType + " | " + beginningTime + " | " + endTime + " | " + lastEventTime + " | " + totalTime + " | ");
}

测试结果

| count | eventType | beginningTime | endTime | lastEventTime | totalTime |
| :------------: | :------------: |
| 323 | 15 | 2020.11.16_12:46:02 | 2020.11.20_01:06:12 | 2020.11.20_00:59:34 | 112197 |
| 322 | 16 | 2020.11.16_12:46:02 | 2020.11.20_01:06:12 | 2020.11.20_00:35:25 | 185469 |
| 173 | 17 | 2020.11.16_12:46:02 | 2020.11.20_01:06:12 | 2020.11.20_00:35:25 | 191812 |
| 174 | 18 | 2020.11.16_12:46:02 | 2020.11.20_01:06:12 | 2020.11.20_00:59:34 | 105847 |

应用事件详细信息

事件包括:切换到前台、切换到后台、时间切换(比如一天的开始结束)、Configuration改变等

queryEvents

UsageEvents queryEvents(long beginTime, long endTime)
UsageEvents queryEventsForSelf(long beginTime, long endTime) //仅返回调用包的事件信息,不需要权限

Query for events in the given time range. Events are only kept by the system for a few days.

UsageEvents

UsageEvents

A result returned from UsageStatsManager.queryEvents(long, long) from which to read UsageEvents.Event objects.

  • public boolean getNextEvent (UsageEvents.Event eventOut):Retrieve the next UsageEvents.Event from the collection and put the resulting data into eventOut.
  • public boolean hasNextEvent ():Returns whether or not there are more events to read using getNextEvent(UsageEvents.Event).

UsageEvents.Event

UsageEvents.Event

An event representing a state change for a component.

通用方法:

  • String getPackageName():The package name of the source of this event.
  • int getEventType():The event type.
  • long getTimeStamp():The time at which this event occurred, measured in milliseconds since the epoch.
  • String getClassName():The class name of the source of this event. This may be null for certain events.

特殊方法:

  • int getAppStandbyBucket():Returns the standby bucket of the app, if the event is of type STANDBY_BUCKET_CHANGED, otherwise returns 0.
  • Configuration getConfiguration():Returns a Configuration for this event if the event is of type CONFIGURATION_CHANGE, otherwise it returns null.
  • String getShortcutId():Returns the ID of a ShortcutInfo for this event if the event is of type SHORTCUT_INVOCATION, otherwise it returns null.

常见的几种事件类型

  • NONE = 0;
  • MOVE_TO_FOREGROUND = 1; //前台,同 ACTIVITY_RESUMED(API 29新增)
  • MOVE_TO_BACKGROUND = 2; //后台,同 ACTIVITY_PAUSED(API 29新增)
  • ACTIVITY_STOPPED = 23; //不可见(API 29新增)
  • END_OF_DAY = 3;
  • CONTINUE_PREVIOUS_DAY = 4;
  • CONFIGURATION_CHANGE = 5;
  • SYSTEM_INTERACTION = 6;
  • USER_INTERACTION = 7;
  • SHORTCUT_INVOCATION = 8;
  • DEVICE_SHUTDOWN = 26;
  • DEVICE_STARTUP = 27;

StandbyBucket

测试代码

private void testEvent(@NonNull Context context) {
    long endTime = System.currentTimeMillis();
    long beginTime = endTime - 1000 * 60 * 60 * 3; //最近3小时
    UsageStatsManager manager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
    UsageEvents usageEvents = manager.queryEventsForSelf(beginTime, endTime);
    
    UsageEvents.Event eventOut;
    while (usageEvents.hasNextEvent()) {
        eventOut = new UsageEvents.Event();
        usageEvents.getNextEvent(eventOut);
        printEventInfo(eventOut);
    }
}
private void printEventInfo(UsageEvents.Event event) {
    DateFormat format = new SimpleDateFormat("yyyy.MM.dd_HH:mm:ss", Locale.getDefault());
    
    String packageName = event.getPackageName();
    String className = event.getClassName();
    int eventType = event.getEventType();
    int standbyBucket = event.getAppStandbyBucket();
    String shortcutId = event.getShortcutId();
    String time = format.format(new Date(event.getTimeStamp()));
    
    Log.i("bqt", "| " + packageName + " | " + className + " | " + eventType + " | " + standbyBucket + " | " + shortcutId + " | " + time + " |");
}

测试结果

| packageName | className | eventType | standbyBucket | shortcutId | time |
| :------------: | :------------: |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:13:56 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_00:13:56 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:13:56 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_00:15:03 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 23 | 0 | null | 2020.11.20_00:15:04 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:15:26 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_00:15:28 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 23 | 0 | null | 2020.11.20_00:15:29 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:16:06 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_00:16:08 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 23 | 0 | null | 2020.11.20_00:16:08 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:16:13 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_00:24:42 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:24:42 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_00:35:25 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 23 | 0 | null | 2020.11.20_00:35:25 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_00:59:34 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 23 | 0 | null | 2020.11.20_01:06:09 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_01:06:11 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_01:06:11 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_01:06:12 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_01:15:50 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 23 | 0 | null | 2020.11.20_01:15:50 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_01:35:39 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_01:35:39 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_01:35:39 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_01:36:22 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_01:36:22 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 2 | 0 | null | 2020.11.20_01:37:08 |
| com.bqt.test.x | com.bqt.test.x.MainActivity | 1 | 0 | null | 2020.11.20_01:37:08 |

其他方法

List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, long endTime)

Gets the hardware configurations the device was in for the given time range, aggregated by the specified interval. The results are ordered as in queryUsageStats(int, long, long).

配置信息包括:orientation、uimode、mcc、mnc、navigation、locale、keyboard等

int getAppStandbyBucket()

Returns the current standby bucket of the calling app. The system determines the standby state of the app based on app usage patterns. Standby buckets determine how much an app will be restricted from running background tasks such as jobs and alarms.

boolean isAppInactive(String packageName)

Returns whether the specified app is currently considered inactive. This will be true if the app hasn't been used directly or indirectly for a period of time defined by the system. This could be of the order of several hours or days.

Apps are not considered inactive when the device is charging.

获取指定的应用程序当前是否为非活动状态。无论我怎么测试,返回值都是false

如何获取该权限

1、在manifest文件中声明该权限

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

只有在清单文件中声明了此权限,才能继续后面的操作

2、跳到系统setting应用中打开相应开关,准许应用获取数据

//public static final String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

3、判断是否具有此权限

常规的判断权限方式无法获取到准确的 UsageStatsManager 权限是否被赋予,以下方法经验证有效

@TargetApi(Build.VERSION_CODES.M)
public static boolean isGrantedUsagePremission(@NonNull Context context) {
    boolean granted;
    AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
    int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), context.getPackageName());

    if (mode == AppOpsManager.MODE_DEFAULT) {
        granted = (context.checkCallingOrSelfPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED);
    } else {
        granted = (mode == AppOpsManager.MODE_ALLOWED);
    }
    return granted;
}

2020-04-23

posted @ 2020-04-23 01:37  白乾涛  阅读(4001)  评论(0编辑  收藏  举报