1 /** 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17 package android.app.usage; 18 19 import android.annotation.RequiresPermission; 20 import android.annotation.SystemApi; 21 import android.annotation.SystemService; 22 import android.content.Context; 23 import android.content.pm.ParceledListSlice; 24 import android.os.RemoteException; 25 import android.os.UserHandle; 26 import android.util.ArrayMap; 27 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * Provides access to device usage history and statistics. Usage data is aggregated into 34 * time intervals: days, weeks, months, and years. 35 * <p /> 36 * When requesting usage data since a particular time, the request might look something like this: 37 * <pre> 38 * PAST REQUEST_TIME TODAY FUTURE 39 * ————————————————————————————||———————————————————————————¦-----------------------| 40 * YEAR || ¦ | 41 * ————————————————————————————||———————————————————————————¦-----------------------| 42 * MONTH | || MONTH ¦ | 43 * ——————————————————|—————————||———————————————————————————¦-----------------------| 44 * | WEEK | WEEK|| | WEEK | WE¦EK | WEEK | 45 * ————————————————————————————||———————————————————|———————¦-----------------------| 46 * || |DAY|DAY|DAY|DAY¦DAY|DAY|DAY|DAY|DAY|DAY| 47 * ————————————————————————————||———————————————————————————¦-----------------------| 48 * </pre> 49 * A request for data in the middle of a time interval will include that interval. 50 * <p/> 51 * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS, which 52 * is a system-level permission and will not be granted to third-party apps. However, declaring 53 * the permission implies intention to use the API and the user of the device can grant permission 54 * through the Settings application. 55 */ 56 @SystemService(Context.USAGE_STATS_SERVICE) 57 public final class UsageStatsManager { 58 59 /** 60 * An interval type that spans a day. See {@link #queryUsageStats(int, long, long)}. 61 */ 62 public static final int INTERVAL_DAILY = 0; 63 64 /** 65 * An interval type that spans a week. See {@link #queryUsageStats(int, long, long)}. 66 */ 67 public static final int INTERVAL_WEEKLY = 1; 68 69 /** 70 * An interval type that spans a month. See {@link #queryUsageStats(int, long, long)}. 71 */ 72 public static final int INTERVAL_MONTHLY = 2; 73 74 /** 75 * An interval type that spans a year. See {@link #queryUsageStats(int, long, long)}. 76 */ 77 public static final int INTERVAL_YEARLY = 3; 78 79 /** 80 * An interval type that will use the best fit interval for the given time range. 81 * See {@link #queryUsageStats(int, long, long)}. 82 */ 83 public static final int INTERVAL_BEST = 4; 84 85 /** 86 * The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it 87 * is a pseudo interval (it actually selects a real interval). 88 * {@hide} 89 */ 90 public static final int INTERVAL_COUNT = 4; 91 92 private static final UsageEvents sEmptyResults = new UsageEvents(); 93 94 private final Context mContext; 95 private final IUsageStatsManager mService; 96 97 /** 98 * {@hide} 99 */ UsageStatsManager(Context context, IUsageStatsManager service)100 public UsageStatsManager(Context context, IUsageStatsManager service) { 101 mContext = context; 102 mService = service; 103 } 104 105 /** 106 * Gets application usage stats for the given time range, aggregated by the specified interval. 107 * <p>The returned list will contain a {@link UsageStats} object for each package that 108 * has data for an interval that is a subset of the time range given. To illustrate:</p> 109 * <pre> 110 * intervalType = INTERVAL_YEARLY 111 * beginTime = 2013 112 * endTime = 2015 (exclusive) 113 * 114 * Results: 115 * 2013 - com.example.alpha 116 * 2013 - com.example.beta 117 * 2014 - com.example.alpha 118 * 2014 - com.example.beta 119 * 2014 - com.example.charlie 120 * </pre> 121 * 122 * @param intervalType The time interval by which the stats are aggregated. 123 * @param beginTime The inclusive beginning of the range of stats to include in the results. 124 * @param endTime The exclusive end of the range of stats to include in the results. 125 * @return A list of {@link UsageStats} or null if none are available. 126 * 127 * @see #INTERVAL_DAILY 128 * @see #INTERVAL_WEEKLY 129 * @see #INTERVAL_MONTHLY 130 * @see #INTERVAL_YEARLY 131 * @see #INTERVAL_BEST 132 */ queryUsageStats(int intervalType, long beginTime, long endTime)133 public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) { 134 try { 135 @SuppressWarnings("unchecked") 136 ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime, 137 endTime, mContext.getOpPackageName()); 138 if (slice != null) { 139 return slice.getList(); 140 } 141 } catch (RemoteException e) { 142 // fallthrough and return null. 143 } 144 return Collections.emptyList(); 145 } 146 147 /** 148 * Gets the hardware configurations the device was in for the given time range, aggregated by 149 * the specified interval. The results are ordered as in 150 * {@link #queryUsageStats(int, long, long)}. 151 * 152 * @param intervalType The time interval by which the stats are aggregated. 153 * @param beginTime The inclusive beginning of the range of stats to include in the results. 154 * @param endTime The exclusive end of the range of stats to include in the results. 155 * @return A list of {@link ConfigurationStats} or null if none are available. 156 */ queryConfigurations(int intervalType, long beginTime, long endTime)157 public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, 158 long endTime) { 159 try { 160 @SuppressWarnings("unchecked") 161 ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats( 162 intervalType, beginTime, endTime, mContext.getOpPackageName()); 163 if (slice != null) { 164 return slice.getList(); 165 } 166 } catch (RemoteException e) { 167 // fallthrough and return the empty list. 168 } 169 return Collections.emptyList(); 170 } 171 172 /** 173 * Query for events in the given time range. Events are only kept by the system for a few 174 * days. 175 * <p /> 176 * <b>NOTE:</b> The last few minutes of the event log will be truncated to prevent abuse 177 * by applications. 178 * 179 * @param beginTime The inclusive beginning of the range of events to include in the results. 180 * @param endTime The exclusive end of the range of events to include in the results. 181 * @return A {@link UsageEvents}. 182 */ queryEvents(long beginTime, long endTime)183 public UsageEvents queryEvents(long beginTime, long endTime) { 184 try { 185 UsageEvents iter = mService.queryEvents(beginTime, endTime, 186 mContext.getOpPackageName()); 187 if (iter != null) { 188 return iter; 189 } 190 } catch (RemoteException e) { 191 // fallthrough and return null 192 } 193 return sEmptyResults; 194 } 195 196 /** 197 * A convenience method that queries for all stats in the given range (using the best interval 198 * for that range), merges the resulting data, and keys it by package name. 199 * See {@link #queryUsageStats(int, long, long)}. 200 * 201 * @param beginTime The inclusive beginning of the range of stats to include in the results. 202 * @param endTime The exclusive end of the range of stats to include in the results. 203 * @return A {@link java.util.Map} keyed by package name, or null if no stats are 204 * available. 205 */ queryAndAggregateUsageStats(long beginTime, long endTime)206 public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) { 207 List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime); 208 if (stats.isEmpty()) { 209 return Collections.emptyMap(); 210 } 211 212 ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>(); 213 final int statCount = stats.size(); 214 for (int i = 0; i < statCount; i++) { 215 UsageStats newStat = stats.get(i); 216 UsageStats existingStat = aggregatedStats.get(newStat.getPackageName()); 217 if (existingStat == null) { 218 aggregatedStats.put(newStat.mPackageName, newStat); 219 } else { 220 existingStat.add(newStat); 221 } 222 } 223 return aggregatedStats; 224 } 225 226 /** 227 * Returns whether the specified app is currently considered inactive. This will be true if the 228 * app hasn't been used directly or indirectly for a period of time defined by the system. This 229 * could be of the order of several hours or days. 230 * @param packageName The package name of the app to query 231 * @return whether the app is currently considered inactive 232 */ isAppInactive(String packageName)233 public boolean isAppInactive(String packageName) { 234 try { 235 return mService.isAppInactive(packageName, UserHandle.myUserId()); 236 } catch (RemoteException e) { 237 // fall through and return default 238 } 239 return false; 240 } 241 242 /** 243 * @hide 244 */ setAppInactive(String packageName, boolean inactive)245 public void setAppInactive(String packageName, boolean inactive) { 246 try { 247 mService.setAppInactive(packageName, inactive, UserHandle.myUserId()); 248 } catch (RemoteException e) { 249 // fall through 250 } 251 } 252 253 /** 254 * {@hide} 255 * Temporarily whitelist the specified app for a short duration. This is to allow an app 256 * receiving a high priority message to be able to access the network and acquire wakelocks 257 * even if the device is in power-save mode or the app is currently considered inactive. 258 * @param packageName The package name of the app to whitelist. 259 * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that 260 * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes. 261 * @param user The user for whom the package should be whitelisted. Passing in a user that is 262 * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission. 263 * @see #isAppInactive(String) 264 */ 265 @SystemApi 266 @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) whitelistAppTemporarily(String packageName, long duration, UserHandle user)267 public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) { 268 try { 269 mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier()); 270 } catch (RemoteException re) { 271 } 272 } 273 274 /** 275 * Inform usage stats that the carrier privileged apps access rules have changed. 276 * @hide 277 */ onCarrierPrivilegedAppsChanged()278 public void onCarrierPrivilegedAppsChanged() { 279 try { 280 mService.onCarrierPrivilegedAppsChanged(); 281 } catch (RemoteException re) { 282 } 283 } 284 285 /** 286 * Reports a Chooser action to the UsageStatsManager. 287 * 288 * @param packageName The package name of the app that is selected. 289 * @param userId The user id of who makes the selection. 290 * @param contentType The type of the content, e.g., Image, Video, App. 291 * @param annotations The annotations of the content, e.g., Game, Selfie. 292 * @param action The action type of Intent that invokes ChooserActivity. 293 * {@link UsageEvents} 294 * @hide 295 */ reportChooserSelection(String packageName, int userId, String contentType, String[] annotations, String action)296 public void reportChooserSelection(String packageName, int userId, String contentType, 297 String[] annotations, String action) { 298 try { 299 mService.reportChooserSelection(packageName, userId, contentType, annotations, action); 300 } catch (RemoteException re) { 301 } 302 } 303 } 304