blob: 4efe0b543b18d6b13654379b21a09f5b21dec916 [file] [log] [blame]
Adam Lesinski35168002014-07-21 15:25:30 -07001/**
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
Adam Lesinski3c153512014-07-23 17:34:34 -070017package com.android.server.usage;
18
Adam Lesinski7f61e962014-09-02 16:43:52 -070019import android.app.usage.ConfigurationStats;
Suprabh Shukla60aa35b2018-04-24 18:52:46 -070020import android.app.usage.EventList;
Dianne Hackbornced54392018-02-26 13:07:42 -080021import android.app.usage.EventStats;
Adam Lesinski35168002014-07-21 15:25:30 -070022import android.app.usage.UsageEvents;
Adam Lesinski3c153512014-07-23 17:34:34 -070023import android.app.usage.UsageStats;
24import android.app.usage.UsageStatsManager;
Adam Lesinski7f61e962014-09-02 16:43:52 -070025import android.content.res.Configuration;
Adam Lesinski66143fa2014-09-11 08:31:05 -070026import android.os.SystemClock;
Adam Lesinski1bb18c42014-08-18 12:21:34 -070027import android.content.Context;
28import android.text.format.DateUtils;
29import android.util.ArrayMap;
Adam Lesinski3c153512014-07-23 17:34:34 -070030import android.util.ArraySet;
31import android.util.Slog;
32
Adam Lesinski1bb18c42014-08-18 12:21:34 -070033import com.android.internal.util.IndentingPrintWriter;
Adam Lesinski7f61e962014-09-02 16:43:52 -070034import com.android.server.usage.UsageStatsDatabase.StatCombiner;
35
Adam Lesinski3c153512014-07-23 17:34:34 -070036import java.io.File;
37import java.io.IOException;
38import java.text.SimpleDateFormat;
Adam Lesinski35168002014-07-21 15:25:30 -070039import java.util.ArrayList;
40import java.util.Arrays;
Adam Lesinski35168002014-07-21 15:25:30 -070041import java.util.List;
Adam Lesinski3c153512014-07-23 17:34:34 -070042
43/**
44 * A per-user UsageStatsService. All methods are meant to be called with the main lock held
45 * in UsageStatsService.
46 */
47class UserUsageStatsService {
48 private static final String TAG = "UsageStatsService";
49 private static final boolean DEBUG = UsageStatsService.DEBUG;
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -080050 private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Adam Lesinski1bb18c42014-08-18 12:21:34 -070051 private static final int sDateFormatFlags =
52 DateUtils.FORMAT_SHOW_DATE
53 | DateUtils.FORMAT_SHOW_TIME
54 | DateUtils.FORMAT_SHOW_YEAR
55 | DateUtils.FORMAT_NUMERIC_DATE;
Adam Lesinski3c153512014-07-23 17:34:34 -070056
Adam Lesinski1bb18c42014-08-18 12:21:34 -070057 private final Context mContext;
Adam Lesinski3c153512014-07-23 17:34:34 -070058 private final UsageStatsDatabase mDatabase;
Adam Lesinski35168002014-07-21 15:25:30 -070059 private final IntervalStats[] mCurrentStats;
Adam Lesinski3c153512014-07-23 17:34:34 -070060 private boolean mStatsChanged = false;
Adam Lesinskid26bea32014-09-03 16:49:59 -070061 private final UnixCalendar mDailyExpiryDate;
Adam Lesinski3c153512014-07-23 17:34:34 -070062 private final StatsUpdatedListener mListener;
63 private final String mLogPrefix;
Amith Yamasanibc813eb2018-03-20 19:37:46 -070064 private String mLastBackgroundedPackage;
Amith Yamasani55717a62015-04-03 17:22:36 -070065 private final int mUserId;
Adam Lesinski3c153512014-07-23 17:34:34 -070066
Adam Lesinski7cba1d42015-08-04 16:17:37 -070067 private static final long[] INTERVAL_LENGTH = new long[] {
68 UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS,
69 UnixCalendar.MONTH_IN_MILLIS, UnixCalendar.YEAR_IN_MILLIS
70 };
71
Adam Lesinski3c153512014-07-23 17:34:34 -070072 interface StatsUpdatedListener {
73 void onStatsUpdated();
Adam Lesinskib2d3ffa2016-01-26 18:18:19 -080074 void onStatsReloaded();
Amith Yamasania93542f2016-02-03 18:02:06 -080075 /**
76 * Callback that a system update was detected
77 * @param mUserId user that needs to be initialized
78 */
79 void onNewUpdate(int mUserId);
Adam Lesinski3c153512014-07-23 17:34:34 -070080 }
81
Amith Yamasanib0ff3222015-03-04 09:56:14 -080082 UserUsageStatsService(Context context, int userId, File usageStatsDir,
83 StatsUpdatedListener listener) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -070084 mContext = context;
Adam Lesinskid26bea32014-09-03 16:49:59 -070085 mDailyExpiryDate = new UnixCalendar(0);
Adam Lesinski3c153512014-07-23 17:34:34 -070086 mDatabase = new UsageStatsDatabase(usageStatsDir);
Adam Lesinski35168002014-07-21 15:25:30 -070087 mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT];
Adam Lesinski3c153512014-07-23 17:34:34 -070088 mListener = listener;
89 mLogPrefix = "User[" + Integer.toString(userId) + "] ";
Amith Yamasani55717a62015-04-03 17:22:36 -070090 mUserId = userId;
Adam Lesinski3c153512014-07-23 17:34:34 -070091 }
92
Amith Yamasania93542f2016-02-03 18:02:06 -080093 void init(final long currentTimeMillis) {
Adam Lesinski66143fa2014-09-11 08:31:05 -070094 mDatabase.init(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -070095
96 int nullCount = 0;
97 for (int i = 0; i < mCurrentStats.length; i++) {
98 mCurrentStats[i] = mDatabase.getLatestUsageStats(i);
99 if (mCurrentStats[i] == null) {
Adam Lesinski35168002014-07-21 15:25:30 -0700100 // Find out how many intervals we don't have data for.
101 // Ideally it should be all or none.
Adam Lesinski3c153512014-07-23 17:34:34 -0700102 nullCount++;
103 }
104 }
105
106 if (nullCount > 0) {
107 if (nullCount != mCurrentStats.length) {
108 // This is weird, but we shouldn't fail if something like this
109 // happens.
110 Slog.w(TAG, mLogPrefix + "Some stats have no latest available");
111 } else {
112 // This must be first boot.
113 }
114
115 // By calling loadActiveStats, we will
116 // generate new stats for each bucket.
Amith Yamasania93542f2016-02-03 18:02:06 -0800117 loadActiveStats(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700118 } else {
119 // Set up the expiry date to be one day from the latest daily stat.
120 // This may actually be today and we will rollover on the first event
121 // that is reported.
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700122 updateRolloverDeadline();
Adam Lesinski3c153512014-07-23 17:34:34 -0700123 }
124
125 // Now close off any events that were open at the time this was saved.
Adam Lesinski35168002014-07-21 15:25:30 -0700126 for (IntervalStats stat : mCurrentStats) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700127 final int pkgCount = stat.packageStats.size();
Adam Lesinski3c153512014-07-23 17:34:34 -0700128 for (int i = 0; i < pkgCount; i++) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700129 UsageStats pkgStats = stat.packageStats.valueAt(i);
Adam Lesinski35168002014-07-21 15:25:30 -0700130 if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND ||
131 pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) {
132 stat.update(pkgStats.mPackageName, stat.lastTimeSaved,
133 UsageEvents.Event.END_OF_DAY);
Adam Lesinski3c153512014-07-23 17:34:34 -0700134 notifyStatsChanged();
135 }
136 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700137
138 stat.updateConfigurationStats(null, stat.lastTimeSaved);
Adam Lesinski3c153512014-07-23 17:34:34 -0700139 }
Amith Yamasani55717a62015-04-03 17:22:36 -0700140
141 if (mDatabase.isNewUpdate()) {
Amith Yamasania93542f2016-02-03 18:02:06 -0800142 notifyNewUpdate();
Amith Yamasani55717a62015-04-03 17:22:36 -0700143 }
144 }
145
Amith Yamasania93542f2016-02-03 18:02:06 -0800146 void onTimeChanged(long oldTime, long newTime) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700147 persistActiveStats();
148 mDatabase.onTimeChanged(newTime - oldTime);
Amith Yamasania93542f2016-02-03 18:02:06 -0800149 loadActiveStats(newTime);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700150 }
151
Amith Yamasania93542f2016-02-03 18:02:06 -0800152 void reportEvent(UsageEvents.Event event) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700153 if (DEBUG) {
Adam Lesinski9d960752014-08-25 14:48:12 -0700154 Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage
Adam Lesinski7f61e962014-09-02 16:43:52 -0700155 + "[" + event.mTimeStamp + "]: "
156 + eventToString(event.mEventType));
Adam Lesinski3c153512014-07-23 17:34:34 -0700157 }
158
Adam Lesinski7f61e962014-09-02 16:43:52 -0700159 if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700160 // Need to rollover
Amith Yamasania93542f2016-02-03 18:02:06 -0800161 rolloverStats(event.mTimeStamp);
Adam Lesinski3c153512014-07-23 17:34:34 -0700162 }
163
Adam Lesinski7f61e962014-09-02 16:43:52 -0700164 final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
165
166 final Configuration newFullConfig = event.mConfiguration;
167 if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE &&
168 currentDailyStats.activeConfiguration != null) {
169 // Make the event configuration a delta.
170 event.mConfiguration = Configuration.generateDelta(
171 currentDailyStats.activeConfiguration, newFullConfig);
Adam Lesinski35168002014-07-21 15:25:30 -0700172 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700173
174 // Add the event to the daily list.
175 if (currentDailyStats.events == null) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700176 currentDailyStats.events = new EventList();
Adam Lesinski7f61e962014-09-02 16:43:52 -0700177 }
Adam Lesinskic8e87292015-06-10 15:33:45 -0700178 if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700179 currentDailyStats.events.insert(event);
Amith Yamasanib0ff3222015-03-04 09:56:14 -0800180 }
Adam Lesinski35168002014-07-21 15:25:30 -0700181
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700182 boolean incrementAppLaunch = false;
183 if (event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
184 if (event.mPackage != null && !event.mPackage.equals(mLastBackgroundedPackage)) {
185 incrementAppLaunch = true;
186 }
187 } else if (event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND) {
188 if (event.mPackage != null) {
189 mLastBackgroundedPackage = event.mPackage;
190 }
191 }
192
Adam Lesinski35168002014-07-21 15:25:30 -0700193 for (IntervalStats stats : mCurrentStats) {
Dianne Hackbornced54392018-02-26 13:07:42 -0800194 switch (event.mEventType) {
195 case UsageEvents.Event.CONFIGURATION_CHANGE: {
196 stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
197 } break;
198 case UsageEvents.Event.CHOOSER_ACTION: {
199 stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction);
200 String[] annotations = event.mContentAnnotations;
201 if (annotations != null) {
202 for (String annotation : annotations) {
203 stats.updateChooserCounts(event.mPackage, annotation, event.mAction);
204 }
Kang Li53b43142016-11-14 14:38:25 -0800205 }
Dianne Hackbornced54392018-02-26 13:07:42 -0800206 } break;
207 case UsageEvents.Event.SCREEN_INTERACTIVE: {
208 stats.updateScreenInteractive(event.mTimeStamp);
209 } break;
210 case UsageEvents.Event.SCREEN_NON_INTERACTIVE: {
211 stats.updateScreenNonInteractive(event.mTimeStamp);
212 } break;
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700213 case UsageEvents.Event.KEYGUARD_SHOWN: {
214 stats.updateKeyguardShown(event.mTimeStamp);
215 } break;
216 case UsageEvents.Event.KEYGUARD_HIDDEN: {
217 stats.updateKeyguardHidden(event.mTimeStamp);
218 } break;
Dianne Hackbornced54392018-02-26 13:07:42 -0800219 default: {
220 stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
221 if (incrementAppLaunch) {
222 stats.incrementAppLaunchCount(event.mPackage);
223 }
224 } break;
Adam Lesinski7f61e962014-09-02 16:43:52 -0700225 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700226 }
227
Amith Yamasanicf768722015-04-23 20:36:41 -0700228 notifyStatsChanged();
229 }
230
Adam Lesinski7f61e962014-09-02 16:43:52 -0700231 private static final StatCombiner<UsageStats> sUsageStatsCombiner =
232 new StatCombiner<UsageStats>() {
233 @Override
234 public void combine(IntervalStats stats, boolean mutable,
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700235 List<UsageStats> accResult) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700236 if (!mutable) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700237 accResult.addAll(stats.packageStats.values());
Adam Lesinski7f61e962014-09-02 16:43:52 -0700238 return;
239 }
240
Adam Lesinski37a46b42014-09-05 15:38:05 -0700241 final int statCount = stats.packageStats.size();
Adam Lesinski7f61e962014-09-02 16:43:52 -0700242 for (int i = 0; i < statCount; i++) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700243 accResult.add(new UsageStats(stats.packageStats.valueAt(i)));
Adam Lesinski7f61e962014-09-02 16:43:52 -0700244 }
245 }
246 };
247
248 private static final StatCombiner<ConfigurationStats> sConfigStatsCombiner =
249 new StatCombiner<ConfigurationStats>() {
250 @Override
251 public void combine(IntervalStats stats, boolean mutable,
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700252 List<ConfigurationStats> accResult) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700253 if (!mutable) {
254 accResult.addAll(stats.configurations.values());
255 return;
256 }
257
258 final int configCount = stats.configurations.size();
259 for (int i = 0; i < configCount; i++) {
260 accResult.add(new ConfigurationStats(stats.configurations.valueAt(i)));
261 }
262 }
263 };
264
Dianne Hackbornced54392018-02-26 13:07:42 -0800265 private static final StatCombiner<EventStats> sEventStatsCombiner =
266 new StatCombiner<EventStats>() {
267 @Override
268 public void combine(IntervalStats stats, boolean mutable,
269 List<EventStats> accResult) {
270 stats.addEventStatsTo(accResult);
271 }
272 };
273
Adam Lesinski7f61e962014-09-02 16:43:52 -0700274 /**
275 * Generic query method that selects the appropriate IntervalStats for the specified time range
276 * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner}
277 * provided to select the stats to use from the IntervalStats object.
278 */
Adam Lesinskid26bea32014-09-03 16:49:59 -0700279 private <T> List<T> queryStats(int intervalType, final long beginTime, final long endTime,
Adam Lesinski7f61e962014-09-02 16:43:52 -0700280 StatCombiner<T> combiner) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700281 if (intervalType == UsageStatsManager.INTERVAL_BEST) {
282 intervalType = mDatabase.findBestFitBucket(beginTime, endTime);
283 if (intervalType < 0) {
284 // Nothing saved to disk yet, so every stat is just as equal (no rollover has
285 // occurred.
286 intervalType = UsageStatsManager.INTERVAL_DAILY;
287 }
Adam Lesinski35168002014-07-21 15:25:30 -0700288 }
289
Adam Lesinskid26bea32014-09-03 16:49:59 -0700290 if (intervalType < 0 || intervalType >= mCurrentStats.length) {
Adam Lesinski35168002014-07-21 15:25:30 -0700291 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700292 Slog.d(TAG, mLogPrefix + "Bad intervalType used " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700293 }
294 return null;
295 }
296
Adam Lesinskid26bea32014-09-03 16:49:59 -0700297 final IntervalStats currentStats = mCurrentStats[intervalType];
Adam Lesinski35168002014-07-21 15:25:30 -0700298
Adam Lesinski3c153512014-07-23 17:34:34 -0700299 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700300 Slog.d(TAG, mLogPrefix + "SELECT * FROM " + intervalType + " WHERE beginTime >= "
Adam Lesinski35168002014-07-21 15:25:30 -0700301 + beginTime + " AND endTime < " + endTime);
Adam Lesinski3c153512014-07-23 17:34:34 -0700302 }
303
Adam Lesinskid26bea32014-09-03 16:49:59 -0700304 if (beginTime >= currentStats.endTime) {
305 if (DEBUG) {
306 Slog.d(TAG, mLogPrefix + "Requesting stats after " + beginTime + " but latest is "
307 + currentStats.endTime);
308 }
309 // Nothing newer available.
310 return null;
311 }
312
313 // Truncate the endTime to just before the in-memory stats. Then, we'll append the
314 // in-memory stats to the results (if necessary) so as to avoid writing to disk too
315 // often.
316 final long truncatedEndTime = Math.min(currentStats.beginTime, endTime);
317
318 // Get the stats from disk.
319 List<T> results = mDatabase.queryUsageStats(intervalType, beginTime,
320 truncatedEndTime, combiner);
Adam Lesinski3c153512014-07-23 17:34:34 -0700321 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700322 Slog.d(TAG, "Got " + (results != null ? results.size() : 0) + " results from disk");
323 Slog.d(TAG, "Current stats beginTime=" + currentStats.beginTime +
324 " endTime=" + currentStats.endTime);
325 }
326
327 // Now check if the in-memory stats match the range and add them if they do.
328 if (beginTime < currentStats.endTime && endTime > currentStats.beginTime) {
329 if (DEBUG) {
330 Slog.d(TAG, mLogPrefix + "Returning in-memory stats");
331 }
332
333 if (results == null) {
334 results = new ArrayList<>();
335 }
336 combiner.combine(currentStats, true, results);
337 }
338
339 if (DEBUG) {
340 Slog.d(TAG, mLogPrefix + "Results: " + (results != null ? results.size() : 0));
Adam Lesinski3c153512014-07-23 17:34:34 -0700341 }
342 return results;
343 }
344
Adam Lesinski7f61e962014-09-02 16:43:52 -0700345 List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) {
346 return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner);
347 }
348
349 List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) {
350 return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
351 }
352
Dianne Hackbornced54392018-02-26 13:07:42 -0800353 List<EventStats> queryEventStats(int bucketType, long beginTime, long endTime) {
354 return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
355 }
356
Makoto Onukiad623012017-05-15 09:29:34 -0700357 UsageEvents queryEvents(final long beginTime, final long endTime,
358 boolean obfuscateInstantApps) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700359 final ArraySet<String> names = new ArraySet<>();
360 List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
361 beginTime, endTime, new StatCombiner<UsageEvents.Event>() {
362 @Override
363 public void combine(IntervalStats stats, boolean mutable,
364 List<UsageEvents.Event> accumulatedResult) {
365 if (stats.events == null) {
366 return;
367 }
Adam Lesinski35168002014-07-21 15:25:30 -0700368
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700369 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700370 final int size = stats.events.size();
371 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700372 if (stats.events.get(i).mTimeStamp >= endTime) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700373 return;
374 }
Adam Lesinski35168002014-07-21 15:25:30 -0700375
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700376 UsageEvents.Event event = stats.events.get(i);
Makoto Onukiad623012017-05-15 09:29:34 -0700377 if (obfuscateInstantApps) {
378 event = event.getObfuscatedIfInstantApp();
379 }
Adam Lesinskid26bea32014-09-03 16:49:59 -0700380 names.add(event.mPackage);
381 if (event.mClass != null) {
382 names.add(event.mClass);
383 }
384 accumulatedResult.add(event);
385 }
386 }
387 });
388
389 if (results == null || results.isEmpty()) {
390 return null;
Adam Lesinski35168002014-07-21 15:25:30 -0700391 }
392
Adam Lesinskid26bea32014-09-03 16:49:59 -0700393 String[] table = names.toArray(new String[names.size()]);
394 Arrays.sort(table);
395 return new UsageEvents(results, table);
Adam Lesinski35168002014-07-21 15:25:30 -0700396 }
397
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800398 UsageEvents queryEventsForPackage(final long beginTime, final long endTime,
399 final String packageName) {
400 final ArraySet<String> names = new ArraySet<>();
401 names.add(packageName);
402 final List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
403 beginTime, endTime, (stats, mutable, accumulatedResult) -> {
404 if (stats.events == null) {
405 return;
406 }
407
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700408 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800409 final int size = stats.events.size();
410 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700411 if (stats.events.get(i).mTimeStamp >= endTime) {
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800412 return;
413 }
414
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700415 final UsageEvents.Event event = stats.events.get(i);
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800416 if (!packageName.equals(event.mPackage)) {
417 continue;
418 }
419 if (event.mClass != null) {
420 names.add(event.mClass);
421 }
422 accumulatedResult.add(event);
423 }
424 });
425
426 if (results == null || results.isEmpty()) {
427 return null;
428 }
429
430 final String[] table = names.toArray(new String[names.size()]);
431 Arrays.sort(table);
432 return new UsageEvents(results, table);
433 }
434
Adam Lesinski3c153512014-07-23 17:34:34 -0700435 void persistActiveStats() {
436 if (mStatsChanged) {
437 Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
438 try {
439 for (int i = 0; i < mCurrentStats.length; i++) {
440 mDatabase.putUsageStats(i, mCurrentStats[i]);
441 }
442 mStatsChanged = false;
443 } catch (IOException e) {
444 Slog.e(TAG, mLogPrefix + "Failed to persist active stats", e);
445 }
446 }
447 }
448
Amith Yamasania93542f2016-02-03 18:02:06 -0800449 private void rolloverStats(final long currentTimeMillis) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700450 final long startTime = SystemClock.elapsedRealtime();
Adam Lesinski3c153512014-07-23 17:34:34 -0700451 Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
452
453 // Finish any ongoing events with an END_OF_DAY event. Make a note of which components
454 // need a new CONTINUE_PREVIOUS_DAY entry.
Adam Lesinski7f61e962014-09-02 16:43:52 -0700455 final Configuration previousConfig =
456 mCurrentStats[UsageStatsManager.INTERVAL_DAILY].activeConfiguration;
Adam Lesinski3c153512014-07-23 17:34:34 -0700457 ArraySet<String> continuePreviousDay = new ArraySet<>();
Adam Lesinski35168002014-07-21 15:25:30 -0700458 for (IntervalStats stat : mCurrentStats) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700459 final int pkgCount = stat.packageStats.size();
Adam Lesinski3c153512014-07-23 17:34:34 -0700460 for (int i = 0; i < pkgCount; i++) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700461 UsageStats pkgStats = stat.packageStats.valueAt(i);
Adam Lesinski35168002014-07-21 15:25:30 -0700462 if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND ||
463 pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700464 continuePreviousDay.add(pkgStats.mPackageName);
Adam Lesinski7f61e962014-09-02 16:43:52 -0700465 stat.update(pkgStats.mPackageName, mDailyExpiryDate.getTimeInMillis() - 1,
466 UsageEvents.Event.END_OF_DAY);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700467 notifyStatsChanged();
Adam Lesinski3c153512014-07-23 17:34:34 -0700468 }
469 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700470
471 stat.updateConfigurationStats(null, mDailyExpiryDate.getTimeInMillis() - 1);
Dianne Hackbornced54392018-02-26 13:07:42 -0800472 stat.commitTime(mDailyExpiryDate.getTimeInMillis() - 1);
Adam Lesinski3c153512014-07-23 17:34:34 -0700473 }
474
475 persistActiveStats();
Adam Lesinski66143fa2014-09-11 08:31:05 -0700476 mDatabase.prune(currentTimeMillis);
Amith Yamasania93542f2016-02-03 18:02:06 -0800477 loadActiveStats(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700478
479 final int continueCount = continuePreviousDay.size();
480 for (int i = 0; i < continueCount; i++) {
481 String name = continuePreviousDay.valueAt(i);
Adam Lesinski7f61e962014-09-02 16:43:52 -0700482 final long beginTime = mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime;
Adam Lesinski35168002014-07-21 15:25:30 -0700483 for (IntervalStats stat : mCurrentStats) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700484 stat.update(name, beginTime, UsageEvents.Event.CONTINUE_PREVIOUS_DAY);
485 stat.updateConfigurationStats(previousConfig, beginTime);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700486 notifyStatsChanged();
Adam Lesinski3c153512014-07-23 17:34:34 -0700487 }
488 }
489 persistActiveStats();
490
Adam Lesinski66143fa2014-09-11 08:31:05 -0700491 final long totalTime = SystemClock.elapsedRealtime() - startTime;
Adam Lesinski3c153512014-07-23 17:34:34 -0700492 Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
493 + " milliseconds");
494 }
495
496 private void notifyStatsChanged() {
497 if (!mStatsChanged) {
498 mStatsChanged = true;
499 mListener.onStatsUpdated();
500 }
501 }
502
Amith Yamasania93542f2016-02-03 18:02:06 -0800503 private void notifyNewUpdate() {
504 mListener.onNewUpdate(mUserId);
505 }
506
507 private void loadActiveStats(final long currentTimeMillis) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700508 for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700509 final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
510 if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
511 currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
Adam Lesinski35168002014-07-21 15:25:30 -0700512 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700513 Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700514 sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +
Adam Lesinskid26bea32014-09-03 16:49:59 -0700515 ") for interval " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700516 }
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700517 mCurrentStats[intervalType] = stats;
Adam Lesinski3c153512014-07-23 17:34:34 -0700518 } else {
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700519 // No good fit remains.
Adam Lesinski35168002014-07-21 15:25:30 -0700520 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700521 Slog.d(TAG, "Creating new stats @ " +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700522 sDateFormat.format(currentTimeMillis) + "(" +
523 currentTimeMillis + ") for interval " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700524 }
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700525
Adam Lesinskid26bea32014-09-03 16:49:59 -0700526 mCurrentStats[intervalType] = new IntervalStats();
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700527 mCurrentStats[intervalType].beginTime = currentTimeMillis;
528 mCurrentStats[intervalType].endTime = currentTimeMillis + 1;
Adam Lesinski3c153512014-07-23 17:34:34 -0700529 }
530 }
Adam Lesinskida4a3772016-01-07 18:24:53 -0800531
Adam Lesinski3c153512014-07-23 17:34:34 -0700532 mStatsChanged = false;
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700533 updateRolloverDeadline();
Adam Lesinskib2d3ffa2016-01-26 18:18:19 -0800534
535 // Tell the listener that the stats reloaded, which may have changed idle states.
536 mListener.onStatsReloaded();
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700537 }
538
539 private void updateRolloverDeadline() {
540 mDailyExpiryDate.setTimeInMillis(
541 mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700542 mDailyExpiryDate.addDays(1);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700543 Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " +
544 sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700545 mDailyExpiryDate.getTimeInMillis() + ")");
Adam Lesinski3c153512014-07-23 17:34:34 -0700546 }
547
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700548 //
549 // -- DUMP related methods --
550 //
551
Amith Yamasania93542f2016-02-03 18:02:06 -0800552 void checkin(final IndentingPrintWriter pw) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700553 mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
554 @Override
555 public boolean checkin(IntervalStats stats) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800556 printIntervalStats(pw, stats, false, false, null);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700557 return true;
558 }
559 });
560 }
561
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700562 void dump(IndentingPrintWriter pw, String pkg) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800563 dump(pw, pkg, false);
564 }
565 void dump(IndentingPrintWriter pw, String pkg, boolean compact) {
566 printLast24HrEvents(pw, !compact, pkg);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700567 for (int interval = 0; interval < mCurrentStats.length; interval++) {
568 pw.print("In-memory ");
569 pw.print(intervalToString(interval));
570 pw.println(" stats");
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800571 printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700572 }
573 }
574
575 private String formatDateTime(long dateTime, boolean pretty) {
576 if (pretty) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800577 return "\"" + sDateFormat.format(dateTime)+ "\"";
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700578 }
579 return Long.toString(dateTime);
580 }
581
582 private String formatElapsedTime(long elapsedTime, boolean pretty) {
583 if (pretty) {
584 return "\"" + DateUtils.formatElapsedTime(elapsedTime / 1000) + "\"";
585 }
586 return Long.toString(elapsedTime);
587 }
588
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800589
590 void printEvent(IndentingPrintWriter pw, UsageEvents.Event event, boolean prettyDates) {
591 pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
592 pw.printPair("type", eventToString(event.mEventType));
593 pw.printPair("package", event.mPackage);
594 if (event.mClass != null) {
595 pw.printPair("class", event.mClass);
596 }
597 if (event.mConfiguration != null) {
598 pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
599 }
600 if (event.mShortcutId != null) {
601 pw.printPair("shortcutId", event.mShortcutId);
602 }
603 if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800604 pw.printPair("standbyBucket", event.getStandbyBucket());
605 pw.printPair("reason", UsageStatsManager.reasonToString(event.getStandbyReason()));
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800606 }
Julia Reynolds5dc1edf2018-06-12 10:19:02 -0400607 if (event.mNotificationChannelId != null) {
608 pw.printPair("channelId", event.mNotificationChannelId);
609 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800610 pw.printHexPair("flags", event.mFlags);
611 pw.println();
612 }
613
614 void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates, final String pkg) {
615 final long endTime = System.currentTimeMillis();
616 UnixCalendar yesterday = new UnixCalendar(endTime);
617 yesterday.addDays(-1);
618
619 final long beginTime = yesterday.getTimeInMillis();
620
621 List<UsageEvents.Event> events = queryStats(UsageStatsManager.INTERVAL_DAILY,
622 beginTime, endTime, new StatCombiner<UsageEvents.Event>() {
623 @Override
624 public void combine(IntervalStats stats, boolean mutable,
625 List<UsageEvents.Event> accumulatedResult) {
626 if (stats.events == null) {
627 return;
628 }
629
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700630 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800631 final int size = stats.events.size();
632 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700633 if (stats.events.get(i).mTimeStamp >= endTime) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800634 return;
635 }
636
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700637 UsageEvents.Event event = stats.events.get(i);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800638 if (pkg != null && !pkg.equals(event.mPackage)) {
639 continue;
640 }
641 accumulatedResult.add(event);
642 }
643 }
644 });
645
646 pw.print("Last 24 hour events (");
647 if (prettyDates) {
648 pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
649 beginTime, endTime, sDateFormatFlags) + "\"");
650 } else {
651 pw.printPair("beginTime", beginTime);
652 pw.printPair("endTime", endTime);
653 }
654 pw.println(")");
Michael Wachenschwanz78646e52018-02-27 15:54:27 -0800655 if (events != null) {
656 pw.increaseIndent();
657 for (UsageEvents.Event event : events) {
658 printEvent(pw, event, prettyDates);
659 }
660 pw.decreaseIndent();
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800661 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800662 }
663
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700664 void printEventAggregation(IndentingPrintWriter pw, String label,
665 IntervalStats.EventTracker tracker, boolean prettyDates) {
666 if (tracker.count != 0 || tracker.duration != 0) {
Dianne Hackbornced54392018-02-26 13:07:42 -0800667 pw.print(label);
668 pw.print(": ");
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700669 pw.print(tracker.count);
Dianne Hackbornced54392018-02-26 13:07:42 -0800670 pw.print("x for ");
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700671 pw.print(formatElapsedTime(tracker.duration, prettyDates));
672 if (tracker.curStartTime != 0) {
673 pw.print(" (now running, started at ");
674 formatDateTime(tracker.curStartTime, prettyDates);
675 pw.print(")");
676 }
Dianne Hackbornced54392018-02-26 13:07:42 -0800677 pw.println();
678 }
679 }
680
Amith Yamasania93542f2016-02-03 18:02:06 -0800681 void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800682 boolean prettyDates, boolean skipEvents, String pkg) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700683 if (prettyDates) {
684 pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
685 stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
686 } else {
687 pw.printPair("beginTime", stats.beginTime);
688 pw.printPair("endTime", stats.endTime);
689 }
690 pw.println();
691 pw.increaseIndent();
692 pw.println("packages");
693 pw.increaseIndent();
694 final ArrayMap<String, UsageStats> pkgStats = stats.packageStats;
695 final int pkgCount = pkgStats.size();
696 for (int i = 0; i < pkgCount; i++) {
697 final UsageStats usageStats = pkgStats.valueAt(i);
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700698 if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
699 continue;
700 }
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700701 pw.printPair("package", usageStats.mPackageName);
Adam Lesinskic8e87292015-06-10 15:33:45 -0700702 pw.printPair("totalTime",
703 formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700704 pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700705 pw.printPair("appLaunchCount", usageStats.mAppLaunchCount);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700706 pw.println();
707 }
708 pw.decreaseIndent();
709
Kang Li53b43142016-11-14 14:38:25 -0800710 pw.println();
Kang Li53b43142016-11-14 14:38:25 -0800711 pw.println("ChooserCounts");
712 pw.increaseIndent();
713 for (UsageStats usageStats : pkgStats.values()) {
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700714 if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
715 continue;
716 }
Kang Li53b43142016-11-14 14:38:25 -0800717 pw.printPair("package", usageStats.mPackageName);
718 if (usageStats.mChooserCounts != null) {
719 final int chooserCountSize = usageStats.mChooserCounts.size();
720 for (int i = 0; i < chooserCountSize; i++) {
721 final String action = usageStats.mChooserCounts.keyAt(i);
722 final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
723 final int annotationSize = counts.size();
724 for (int j = 0; j < annotationSize; j++) {
725 final String key = counts.keyAt(j);
726 final int count = counts.valueAt(j);
727 if (count != 0) {
728 pw.printPair("ChooserCounts", action + ":" + key + " is " +
729 Integer.toString(count));
730 pw.println();
731 }
732 }
733 }
734 }
735 pw.println();
736 }
Amith Yamasani61d5fd72017-02-24 11:02:07 -0800737 pw.decreaseIndent();
Kang Li53b43142016-11-14 14:38:25 -0800738
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700739 if (pkg == null) {
740 pw.println("configurations");
741 pw.increaseIndent();
742 final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
743 final int configCount = configStats.size();
744 for (int i = 0; i < configCount; i++) {
745 final ConfigurationStats config = configStats.valueAt(i);
746 pw.printPair("config", Configuration.resourceQualifierString(
747 config.mConfiguration));
748 pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
749 pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
750 pw.printPair("count", config.mActivationCount);
751 pw.println();
752 }
753 pw.decreaseIndent();
Dianne Hackbornced54392018-02-26 13:07:42 -0800754 pw.println("event aggregations");
755 pw.increaseIndent();
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700756 printEventAggregation(pw, "screen-interactive", stats.interactiveTracker,
757 prettyDates);
758 printEventAggregation(pw, "screen-non-interactive", stats.nonInteractiveTracker,
759 prettyDates);
760 printEventAggregation(pw, "keyguard-shown", stats.keyguardShownTracker,
761 prettyDates);
762 printEventAggregation(pw, "keyguard-hidden", stats.keyguardHiddenTracker,
763 prettyDates);
Dianne Hackbornced54392018-02-26 13:07:42 -0800764 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700765 }
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700766
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800767 // The last 24 hours of events is already printed in the non checkin dump
768 // No need to repeat here.
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800769 if (!skipEvents) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800770 pw.println("events");
771 pw.increaseIndent();
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700772 final EventList events = stats.events;
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800773 final int eventCount = events != null ? events.size() : 0;
774 for (int i = 0; i < eventCount; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700775 final UsageEvents.Event event = events.get(i);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800776 if (pkg != null && !pkg.equals(event.mPackage)) {
777 continue;
778 }
779 printEvent(pw, event, prettyDates);
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700780 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800781 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700782 }
783 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700784 }
785
786 private static String intervalToString(int interval) {
787 switch (interval) {
788 case UsageStatsManager.INTERVAL_DAILY:
789 return "daily";
790 case UsageStatsManager.INTERVAL_WEEKLY:
791 return "weekly";
792 case UsageStatsManager.INTERVAL_MONTHLY:
793 return "monthly";
794 case UsageStatsManager.INTERVAL_YEARLY:
795 return "yearly";
796 default:
797 return "?";
798 }
799 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700800
801 private static String eventToString(int eventType) {
802 switch (eventType) {
Adam Lesinski35168002014-07-21 15:25:30 -0700803 case UsageEvents.Event.NONE:
Adam Lesinski3c153512014-07-23 17:34:34 -0700804 return "NONE";
Adam Lesinski35168002014-07-21 15:25:30 -0700805 case UsageEvents.Event.MOVE_TO_BACKGROUND:
Adam Lesinski3c153512014-07-23 17:34:34 -0700806 return "MOVE_TO_BACKGROUND";
Adam Lesinski35168002014-07-21 15:25:30 -0700807 case UsageEvents.Event.MOVE_TO_FOREGROUND:
Adam Lesinski3c153512014-07-23 17:34:34 -0700808 return "MOVE_TO_FOREGROUND";
Adam Lesinski35168002014-07-21 15:25:30 -0700809 case UsageEvents.Event.END_OF_DAY:
Adam Lesinski3c153512014-07-23 17:34:34 -0700810 return "END_OF_DAY";
Adam Lesinski35168002014-07-21 15:25:30 -0700811 case UsageEvents.Event.CONTINUE_PREVIOUS_DAY:
Adam Lesinski3c153512014-07-23 17:34:34 -0700812 return "CONTINUE_PREVIOUS_DAY";
Adam Lesinski7f61e962014-09-02 16:43:52 -0700813 case UsageEvents.Event.CONFIGURATION_CHANGE:
814 return "CONFIGURATION_CHANGE";
Adam Lesinskic8e87292015-06-10 15:33:45 -0700815 case UsageEvents.Event.SYSTEM_INTERACTION:
816 return "SYSTEM_INTERACTION";
817 case UsageEvents.Event.USER_INTERACTION:
818 return "USER_INTERACTION";
Makoto Onukiac042502016-05-20 16:39:42 -0700819 case UsageEvents.Event.SHORTCUT_INVOCATION:
820 return "SHORTCUT_INVOCATION";
Kang Li53b43142016-11-14 14:38:25 -0800821 case UsageEvents.Event.CHOOSER_ACTION:
822 return "CHOOSER_ACTION";
Amith Yamasani803eab692017-11-09 17:47:04 -0800823 case UsageEvents.Event.NOTIFICATION_SEEN:
824 return "NOTIFICATION_SEEN";
Amith Yamasanibfc4bf52018-01-19 06:55:08 -0800825 case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
826 return "STANDBY_BUCKET_CHANGED";
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500827 case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
828 return "NOTIFICATION_INTERRUPTION";
Jason Monk1918ef72018-03-14 09:20:39 -0400829 case UsageEvents.Event.SLICE_PINNED:
830 return "SLICE_PINNED";
831 case UsageEvents.Event.SLICE_PINNED_PRIV:
832 return "SLICE_PINNED_PRIV";
Dianne Hackbornced54392018-02-26 13:07:42 -0800833 case UsageEvents.Event.SCREEN_INTERACTIVE:
834 return "SCREEN_INTERACTIVE";
835 case UsageEvents.Event.SCREEN_NON_INTERACTIVE:
836 return "SCREEN_NON_INTERACTIVE";
Adam Lesinski3c153512014-07-23 17:34:34 -0700837 default:
838 return "UNKNOWN";
839 }
840 }
Ritesh Reddy8a6ce2c2015-12-17 17:03:54 +0000841
842 byte[] getBackupPayload(String key){
843 return mDatabase.getBackupPayload(key);
844 }
845
846 void applyRestoredPayload(String key, byte[] payload){
847 mDatabase.applyRestoredPayload(key, payload);
848 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700849}