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.content.Context; 20 import android.content.pm.ParceledListSlice; 21 import android.os.RemoteException; 22 import android.util.ArrayMap; 23 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.Map; 27 28 /** 29 * Provides access to device usage history and statistics. Usage data is aggregated into 30 * time intervals: days, weeks, months, and years. 31 * <p /> 32 * When requesting usage data since a particular time, the request might look something like this: 33 * <pre> 34 * PAST REQUEST_TIME TODAY FUTURE 35 * ||-----------------------| 36 * YEAR || | 37 * ||-----------------------| 38 * MONTH | || MONTH | 39 * |||-----------------------| 40 * | WEEK | WEEK|| | WEEK | WEEK | WEEK | 41 * |||-----------------------| 42 * || |DAY|DAY|DAY|DAYDAY|DAY|DAY|DAY|DAY|DAY| 43 * ||-----------------------| 44 * </pre> 45 * A request for data in the middle of a time interval will include that interval. 46 * <p/> 47 * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS, which 48 * is a system-level permission and will not be granted to third-party apps. However, declaring 49 * the permission implies intention to use the API and the user of the device can grant permission 50 * through the Settings application. 51 */ 52 public final class UsageStatsManager { 53 54 /** 55 * An interval type that spans a day. See {@link #queryUsageStats(int, long, long)}. 56 */ 57 public static final int INTERVAL_DAILY = 0; 58 59 /** 60 * An interval type that spans a week. See {@link #queryUsageStats(int, long, long)}. 61 */ 62 public static final int INTERVAL_WEEKLY = 1; 63 64 /** 65 * An interval type that spans a month. See {@link #queryUsageStats(int, long, long)}. 66 */ 67 public static final int INTERVAL_MONTHLY = 2; 68 69 /** 70 * An interval type that spans a year. See {@link #queryUsageStats(int, long, long)}. 71 */ 72 public static final int INTERVAL_YEARLY = 3; 73 74 /** 75 * An interval type that will use the best fit interval for the given time range. 76 * See {@link #queryUsageStats(int, long, long)}. 77 */ 78 public static final int INTERVAL_BEST = 4; 79 80 /** 81 * The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it 82 * is a pseudo interval (it actually selects a real interval). 83 * {@hide} 84 */ 85 public static final int INTERVAL_COUNT = 4; 86 87 private static final UsageEvents sEmptyResults = new UsageEvents(); 88 89 private final Context mContext; 90 private final IUsageStatsManager mService; 91 92 /** 93 * {@hide} 94 */ 95 public UsageStatsManager(Context context, IUsageStatsManager service) { 96 mContext = context; 97 mService = service; 98 } 99 100 /** 101 * Gets application usage stats for the given time range, aggregated by the specified interval. 102 * <p>The returned list will contain a {@link UsageStats} object for each package that 103 * has data for an interval that is a subset of the time range given. To illustrate:</p> 104 * <pre> 105 * intervalType = INTERVAL_YEARLY 106 * beginTime = 2013 107 * endTime = 2015 (exclusive) 108 * 109 * Results: 110 * 2013 - com.example.alpha 111 * 2013 - com.example.beta 112 * 2014 - com.example.alpha 113 * 2014 - com.example.beta 114 * 2014 - com.example.charlie 115 * </pre> 116 * 117 * @param intervalType The time interval by which the stats are aggregated. 118 * @param beginTime The inclusive beginning of the range of stats to include in the results. 119 * @param endTime The exclusive end of the range of stats to include in the results. 120 * @return A list of {@link UsageStats} or null if none are available. 121 * 122 * @see #INTERVAL_DAILY 123 * @see #INTERVAL_WEEKLY 124 * @see #INTERVAL_MONTHLY 125 * @see #INTERVAL_YEARLY 126 * @see #INTERVAL_BEST 127 */ 128 public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) { 129 try { 130 @SuppressWarnings("unchecked") 131 ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime, 132 endTime, mContext.getOpPackageName()); 133 if (slice != null) { 134 return slice.getList(); 135 } 136 } catch (RemoteException e) { 137 // fallthrough and return null. 138 } 139 return Collections.emptyList(); 140 } 141 142 /** 143 * Gets the hardware configurations the device was in for the given time range, aggregated by 144 * the specified interval. The results are ordered as in 145 * {@link #queryUsageStats(int, long, long)}. 146 * 147 * @param intervalType The time interval by which the stats are aggregated. 148 * @param beginTime The inclusive beginning of the range of stats to include in the results. 149 * @param endTime The exclusive end of the range of stats to include in the results. 150 * @return A list of {@link ConfigurationStats} or null if none are available. 151 */ 152 public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, 153 long endTime) { 154 try { 155 @SuppressWarnings("unchecked") 156 ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats( 157 intervalType, beginTime, endTime, mContext.getOpPackageName()); 158 if (slice != null) { 159 return slice.getList(); 160 } 161 } catch (RemoteException e) { 162 // fallthrough and return the empty list. 163 } 164 return Collections.emptyList(); 165 } 166 167 /** 168 * Query for events in the given time range. Events are only kept by the system for a few 169 * days. 170 * <p /> 171 * <b>NOTE:</b> The last few minutes of the event log will be truncated to prevent abuse 172 * by applications. 173 * 174 * @param beginTime The inclusive beginning of the range of events to include in the results. 175 * @param endTime The exclusive end of the range of events to include in the results. 176 * @return A {@link UsageEvents}. 177 */ 178 public UsageEvents queryEvents(long beginTime, long endTime) { 179 try { 180 UsageEvents iter = mService.queryEvents(beginTime, endTime, 181 mContext.getOpPackageName()); 182 if (iter != null) { 183 return iter; 184 } 185 } catch (RemoteException e) { 186 // fallthrough and return null 187 } 188 return sEmptyResults; 189 } 190 191 /** 192 * A convenience method that queries for all stats in the given range (using the best interval 193 * for that range), merges the resulting data, and keys it by package name. 194 * See {@link #queryUsageStats(int, long, long)}. 195 * 196 * @param beginTime The inclusive beginning of the range of stats to include in the results. 197 * @param endTime The exclusive end of the range of stats to include in the results. 198 * @return A {@link java.util.Map} keyed by package name, or null if no stats are 199 * available. 200 */ 201 public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) { 202 List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime); 203 if (stats.isEmpty()) { 204 return Collections.emptyMap(); 205 } 206 207 ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>(); 208 final int statCount = stats.size(); 209 for (int i = 0; i < statCount; i++) { 210 UsageStats newStat = stats.get(i); 211 UsageStats existingStat = aggregatedStats.get(newStat.getPackageName()); 212 if (existingStat == null) { 213 aggregatedStats.put(newStat.mPackageName, newStat); 214 } else { 215 existingStat.add(newStat); 216 } 217 } 218 return aggregatedStats; 219 } 220 } 221