13516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/** 23516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Copyright (C) 2014 The Android Open Source Project 33516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 43516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not 53516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * use this file except in compliance with the License. You may obtain a copy 63516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * of the License at 73516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 83516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 93516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Unless required by applicable law or agreed to in writing, software 113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * License for the specific language governing permissions and limitations 143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * under the License. 153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 163516800b611a79339a3c188332d13a26e9086b09Adam Lesinskipackage com.android.server.usage; 173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 183516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport com.android.internal.util.XmlUtils; 193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 203516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.xmlpull.v1.XmlPullParser; 213516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException; 227f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport org.xmlpull.v1.XmlSerializer; 233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 247f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.app.usage.ConfigurationStats; 253516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.TimeSparseArray; 263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents; 273516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageStats; 287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.content.res.Configuration; 29ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onukiimport android.text.TextUtils; 3053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Liimport android.util.ArrayMap; 31ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onukiimport android.util.Log; 32ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onukiimport android.util.LogWriter; 333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 343516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.io.IOException; 353516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.net.ProtocolException; 363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/** 383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * UsageStats reader/writer for version 1 of the XML format. 393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 403516800b611a79339a3c188332d13a26e9086b09Adam Lesinskifinal class UsageStatsXmlV1 { 41ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki private static final String TAG = "UsageStatsXmlV1"; 42ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki 4337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String PACKAGES_TAG = "packages"; 447f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static final String PACKAGE_TAG = "package"; 4537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 4653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static final String CHOOSER_COUNT_TAG = "chosen_action"; 4753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static final String CATEGORY_TAG = "category"; 4853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static final String NAME = "name"; 4953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static final String COUNT = "count"; 5053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li 5137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String CONFIGURATIONS_TAG = "configurations"; 5237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String CONFIG_TAG = "config"; 5337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 547f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static final String EVENT_LOG_TAG = "event-log"; 5537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String EVENT_TAG = "event"; 567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 5737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Attributes 589d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski private static final String PACKAGE_ATTR = "package"; 59ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki private static final String FLAGS_ATTR = "flags"; 609d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski private static final String CLASS_ATTR = "class"; 6137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String TOTAL_TIME_ACTIVE_ATTR = "timeActive"; 627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static final String COUNT_ATTR = "count"; 637f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static final String ACTIVE_ATTR = "active"; 643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private static final String LAST_EVENT_ATTR = "lastEvent"; 653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private static final String TYPE_ATTR = "type"; 66ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki private static final String SHORTCUT_ID_ATTR = "shortcutId"; 6737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 6837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Time attributes stored as an offset of the beginTime. 6937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive"; 7037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static final String END_TIME_ATTR = "endTime"; 713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private static final String TIME_ATTR = "time"; 723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 737f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut) 7453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li throws XmlPullParserException, IOException { 7537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final String pkg = parser.getAttributeValue(null, PACKAGE_ATTR); 7637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski if (pkg == null) { 7737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present"); 783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 7937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final UsageStats stats = statsOut.getOrCreateUsageStats(pkg); 8037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 8137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Apply the offset to the beginTime to find the absolute time. 8237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute( 8337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski parser, LAST_TIME_ACTIVE_ATTR); 843516800b611a79339a3c188332d13a26e9086b09Adam Lesinski stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); 853516800b611a79339a3c188332d13a26e9086b09Adam Lesinski stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR); 8653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li int eventCode; 8753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) { 8853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li final String tag = parser.getName(); 8953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (eventCode == XmlPullParser.END_TAG && tag.equals(PACKAGE_TAG)) { 9053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li break; 9153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 9253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (eventCode != XmlPullParser.START_TAG) { 9353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li continue; 9453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 9553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (tag.equals(CHOOSER_COUNT_TAG)) { 9653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li String action = XmlUtils.readStringAttribute(parser, NAME); 9753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li loadChooserCounts(parser, stats, action); 9853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 9953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 10053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 10153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li 10253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static void loadChooserCounts( 10353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li XmlPullParser parser, UsageStats usageStats, String action) 10453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li throws XmlPullParserException, IOException { 10553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (action == null) { 10653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li return; 10753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 10853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (usageStats.mChooserCounts == null) { 10953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li usageStats.mChooserCounts = new ArrayMap<>(); 11053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 11153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (!usageStats.mChooserCounts.containsKey(action)) { 11253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li ArrayMap<String, Integer> counts = new ArrayMap<>(); 11353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li usageStats.mChooserCounts.put(action, counts); 11453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 11553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li 11653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li int eventCode; 11753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) { 11853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li final String tag = parser.getName(); 11953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (eventCode == XmlPullParser.END_TAG && tag.equals(CHOOSER_COUNT_TAG)) { 12053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li break; 12153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 12253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (eventCode != XmlPullParser.START_TAG) { 12353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li continue; 12453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 12553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (tag.equals(CATEGORY_TAG)) { 12653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li String category = XmlUtils.readStringAttribute(parser, NAME); 12753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li int count = XmlUtils.readIntAttribute(parser, COUNT); 12853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li usageStats.mChooserCounts.get(action).put(category, count); 12953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 13053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 1313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1337f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static void loadConfigStats(XmlPullParser parser, IntervalStats statsOut) 1343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski throws XmlPullParserException, IOException { 1357f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final Configuration config = new Configuration(); 1367f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski Configuration.readXmlAttrs(parser, config); 1377f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 13837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final ConfigurationStats configStats = statsOut.getOrCreateConfigurationStats(config); 13937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 14037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Apply the offset to the beginTime to find the absolute time. 14137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski configStats.mLastTimeActive = statsOut.beginTime + XmlUtils.readLongAttribute( 14237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski parser, LAST_TIME_ACTIVE_ATTR); 14337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 1447f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mTotalTimeActive = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); 1457f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mActivationCount = XmlUtils.readIntAttribute(parser, COUNT_ATTR); 1467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (XmlUtils.readBooleanAttribute(parser, ACTIVE_ATTR)) { 1477f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski statsOut.activeConfiguration = configStats.mConfiguration; 1483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1497f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1517f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static void loadEvent(XmlPullParser parser, IntervalStats statsOut) 1527f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski throws XmlPullParserException, IOException { 15337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final String packageName = XmlUtils.readStringAttribute(parser, PACKAGE_ATTR); 1549d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski if (packageName == null) { 15537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present"); 1563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 15737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final String className = XmlUtils.readStringAttribute(parser, CLASS_ATTR); 1587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 15937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final UsageEvents.Event event = statsOut.buildEvent(packageName, className); 16037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 161ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki event.mFlags = XmlUtils.readIntAttribute(parser, FLAGS_ATTR, 0); 162ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki 16337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Apply the offset to the beginTime to find the absolute time of this event. 16437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski event.mTimeStamp = statsOut.beginTime + XmlUtils.readLongAttribute(parser, TIME_ATTR); 16537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 16637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR); 167ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki switch (event.mEventType) { 168ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki case UsageEvents.Event.CONFIGURATION_CHANGE: 169ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki event.mConfiguration = new Configuration(); 170ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki Configuration.readXmlAttrs(parser, event.mConfiguration); 171ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki break; 172ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki case UsageEvents.Event.SHORTCUT_INVOCATION: 173ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki final String id = XmlUtils.readStringAttribute(parser, SHORTCUT_ID_ATTR); 174ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki event.mShortcutId = (id != null) ? id.intern() : null; 175ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki break; 1767f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1787f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (statsOut.events == null) { 1797f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski statsOut.events = new TimeSparseArray<>(); 1807f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1817f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski statsOut.events.put(event.mTimeStamp, event); 1823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 18437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static void writeUsageStats(XmlSerializer xml, final IntervalStats stats, 18537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final UsageStats usageStats) throws IOException { 1867f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski xml.startTag(null, PACKAGE_TAG); 18737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 18837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Write the time offset. 18937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, 19037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski usageStats.mLastTimeUsed - stats.beginTime); 19137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 19237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName); 19337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground); 19437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent); 19553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li writeChooserCounts(xml, usageStats); 1967f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski xml.endTag(null, PACKAGE_TAG); 1977f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1987f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 19953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static void writeChooserCounts(XmlSerializer xml, final UsageStats usageStats) 20053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li throws IOException { 20153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (usageStats == null || usageStats.mChooserCounts == null || 20253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li usageStats.mChooserCounts.keySet().isEmpty()) { 20353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li return; 20453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 20553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li final int chooserCountSize = usageStats.mChooserCounts.size(); 20653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li for (int i = 0; i < chooserCountSize; i++) { 20753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li final String action = usageStats.mChooserCounts.keyAt(i); 20853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i); 20953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (action == null || counts == null || counts.isEmpty()) { 21053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li continue; 21153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 21253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li xml.startTag(null, CHOOSER_COUNT_TAG); 21353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li XmlUtils.writeStringAttribute(xml, NAME, action); 21453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li writeCountsForAction(xml, counts); 21553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li xml.endTag(null, CHOOSER_COUNT_TAG); 21653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 21753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 21853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li 21953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li private static void writeCountsForAction(XmlSerializer xml, ArrayMap<String, Integer> counts) 22053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li throws IOException { 22153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li final int countsSize = counts.size(); 22253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li for (int i = 0; i < countsSize; i++) { 22353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li String key = counts.keyAt(i); 22453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li int count = counts.valueAt(i); 22553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li if (count > 0) { 22653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li xml.startTag(null, CATEGORY_TAG); 22753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li XmlUtils.writeStringAttribute(xml, NAME, key); 22853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li XmlUtils.writeIntAttribute(xml, COUNT, count); 22953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li xml.endTag(null, CATEGORY_TAG); 23053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 23153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 23253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li } 23353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li 23437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static void writeConfigStats(XmlSerializer xml, final IntervalStats stats, 23537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final ConfigurationStats configStats, boolean isActive) throws IOException { 23637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.startTag(null, CONFIG_TAG); 23737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 23837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Write the time offset. 23937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, 24037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski configStats.mLastTimeActive - stats.beginTime); 24137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 24237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, configStats.mTotalTimeActive); 24337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeIntAttribute(xml, COUNT_ATTR, configStats.mActivationCount); 2447f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (isActive) { 2457f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski XmlUtils.writeBooleanAttribute(xml, ACTIVE_ATTR, true); 2467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 2477f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 2487f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski // Now write the attributes representing the configuration object. 24937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski Configuration.writeXmlAttrs(xml, configStats.mConfiguration); 2507f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 25137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.endTag(null, CONFIG_TAG); 2523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 25437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski private static void writeEvent(XmlSerializer xml, final IntervalStats stats, 25537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final UsageEvents.Event event) throws IOException { 25637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.startTag(null, EVENT_TAG); 25737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 25837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski // Store the time offset. 25937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeLongAttribute(xml, TIME_ATTR, event.mTimeStamp - stats.beginTime); 26037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski 2617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, event.mPackage); 2629d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski if (event.mClass != null) { 2637f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass); 2647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 265ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki XmlUtils.writeIntAttribute(xml, FLAGS_ATTR, event.mFlags); 2667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType); 2677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 268ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki switch (event.mEventType) { 269ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki case UsageEvents.Event.CONFIGURATION_CHANGE: 270ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki if (event.mConfiguration != null) { 271ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki Configuration.writeXmlAttrs(xml, event.mConfiguration); 272ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki } 273ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki break; 274ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki case UsageEvents.Event.SHORTCUT_INVOCATION: 275ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki if (event.mShortcutId != null) { 276ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki XmlUtils.writeStringAttribute(xml, SHORTCUT_ID_ATTR, event.mShortcutId); 277ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki } 278ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki break; 2799d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 2807f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 28137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.endTag(null, EVENT_TAG); 2823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 2843516800b611a79339a3c188332d13a26e9086b09Adam Lesinski /** 2853516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Reads from the {@link XmlPullParser}, assuming that it is already on the 2863516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * <code><usagestats></code> tag. 2873516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 2883516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * @param parser The parser from which to read events. 2893516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * @param statsOut The stats object to populate with the data from the XML file. 2903516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 2913516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public static void read(XmlPullParser parser, IntervalStats statsOut) 2923516800b611a79339a3c188332d13a26e9086b09Adam Lesinski throws XmlPullParserException, IOException { 29337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski statsOut.packageStats.clear(); 2947f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski statsOut.configurations.clear(); 2957f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski statsOut.activeConfiguration = null; 2963516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 2973516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (statsOut.events != null) { 2983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski statsOut.events.clear(); 2993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3003516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 301690f78adf1737b2356d341b46f21a4e2d5df58ebEdward Cunningham statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR); 3023516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 3037f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski int eventCode; 3047f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski int outerDepth = parser.getDepth(); 3057f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT 3067f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski && (eventCode != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 3077f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (eventCode != XmlPullParser.START_TAG) { 3087f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski continue; 3097f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 3107f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 3117f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final String tag = parser.getName(); 3127f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski switch (tag) { 3137f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski case PACKAGE_TAG: 3147f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski loadUsageStats(parser, statsOut); 3157f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski break; 3163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 31737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski case CONFIG_TAG: 3187f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski loadConfigStats(parser, statsOut); 3197f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski break; 3207f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 32137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski case EVENT_TAG: 3227f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski loadEvent(parser, statsOut); 3237f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski break; 3243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 3283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski /** 32937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski * Writes the stats object to an XML file. The {@link XmlSerializer} 3303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * has already written the <code><usagestats></code> tag, but attributes may still 3313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * be added. 3323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 33337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski * @param xml The serializer to which to write the packageStats data. 3343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * @param stats The stats object to write to the XML file. 3353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 33637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski public static void write(XmlSerializer xml, IntervalStats stats) throws IOException { 33737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime); 3383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 33937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.startTag(null, PACKAGES_TAG); 34037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final int statsCount = stats.packageStats.size(); 3413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski for (int i = 0; i < statsCount; i++) { 34237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski writeUsageStats(xml, stats, stats.packageStats.valueAt(i)); 3433516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 34437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.endTag(null, PACKAGES_TAG); 3453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 34637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.startTag(null, CONFIGURATIONS_TAG); 3477f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final int configCount = stats.configurations.size(); 3487f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski for (int i = 0; i < configCount; i++) { 3497f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i)); 35037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski writeConfigStats(xml, stats, stats.configurations.valueAt(i), active); 3517f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 35237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.endTag(null, CONFIGURATIONS_TAG); 3537f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 35437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.startTag(null, EVENT_LOG_TAG); 3557f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final int eventCount = stats.events != null ? stats.events.size() : 0; 3567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski for (int i = 0; i < eventCount; i++) { 35737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski writeEvent(xml, stats, stats.events.valueAt(i)); 3583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 35937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski xml.endTag(null, EVENT_LOG_TAG); 3603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 3623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private UsageStatsXmlV1() { 3633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski} 365