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