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;
2560aa35b756707a16d310c222a36edbcef9d56ed4Suprabh Shuklaimport android.app.usage.EventList;
263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents;
273516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageStats;
287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.content.res.Configuration;
2953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Liimport android.util.ArrayMap;
303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
313516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.io.IOException;
323516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.net.ProtocolException;
333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/**
353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * UsageStats reader/writer for version 1 of the XML format.
363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */
373516800b611a79339a3c188332d13a26e9086b09Adam Lesinskifinal class UsageStatsXmlV1 {
38ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki    private static final String TAG = "UsageStatsXmlV1";
39ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki
40ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn    private static final String INTERACTIVE_TAG = "interactive";
41ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn    private static final String NON_INTERACTIVE_TAG = "non-interactive";
423378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn    private static final String KEYGUARD_SHOWN_TAG = "keyguard-shown";
433378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn    private static final String KEYGUARD_HIDDEN_TAG = "keyguard-hidden";
44ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn
4537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String PACKAGES_TAG = "packages";
467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String PACKAGE_TAG = "package";
4737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
4853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static final String CHOOSER_COUNT_TAG = "chosen_action";
4953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static final String CATEGORY_TAG = "category";
5053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static final String NAME = "name";
5153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static final String COUNT = "count";
5253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li
5337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String CONFIGURATIONS_TAG = "configurations";
5437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String CONFIG_TAG = "config";
5537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String EVENT_LOG_TAG = "event-log";
5737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String EVENT_TAG = "event";
587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
5937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    // Attributes
609d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski    private static final String PACKAGE_ATTR = "package";
61ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki    private static final String FLAGS_ATTR = "flags";
629d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski    private static final String CLASS_ATTR = "class";
6337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String TOTAL_TIME_ACTIVE_ATTR = "timeActive";
647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String COUNT_ATTR = "count";
657f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String ACTIVE_ATTR = "active";
663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String LAST_EVENT_ATTR = "lastEvent";
673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TYPE_ATTR = "type";
68ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki    private static final String SHORTCUT_ID_ATTR = "shortcutId";
69bfc4bf5febe3d97d3f51206c9ead2f7d2b05e700Amith Yamasani    private static final String STANDBY_BUCKET_ATTR = "standbyBucket";
70bc813eb26e3027856114a26312e36e4bad86bd86Amith Yamasani    private static final String APP_LAUNCH_COUNT_ATTR = "appLaunchCount";
7137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
7237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    // Time attributes stored as an offset of the beginTime.
7337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
7437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static final String END_TIME_ATTR = "endTime";
753516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TIME_ATTR = "time";
763516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut)
7853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            throws XmlPullParserException, IOException {
7937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final String pkg = parser.getAttributeValue(null, PACKAGE_ATTR);
8037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        if (pkg == null) {
8137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
8337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final UsageStats stats = statsOut.getOrCreateUsageStats(pkg);
8437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
8537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        // Apply the offset to the beginTime to find the absolute time.
8637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
8737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski                parser, LAST_TIME_ACTIVE_ATTR);
883516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
893516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
90bc813eb26e3027856114a26312e36e4bad86bd86Amith Yamasani        stats.mAppLaunchCount = XmlUtils.readIntAttribute(parser, APP_LAUNCH_COUNT_ATTR, 0);
9153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        int eventCode;
9253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) {
9353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            final String tag = parser.getName();
9453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (eventCode == XmlPullParser.END_TAG && tag.equals(PACKAGE_TAG)) {
9553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                break;
9653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
9753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (eventCode != XmlPullParser.START_TAG) {
9853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                continue;
9953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
10053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (tag.equals(CHOOSER_COUNT_TAG)) {
10153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                String action = XmlUtils.readStringAttribute(parser, NAME);
10253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                loadChooserCounts(parser, stats, action);
10353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
10453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
10553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    }
10653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li
1073378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn    private static void loadCountAndTime(XmlPullParser parser,
1083378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn            IntervalStats.EventTracker tracker)
109ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn            throws IOException, XmlPullParserException {
1103378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn        tracker.count = XmlUtils.readIntAttribute(parser, COUNT_ATTR, 0);
1113378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn        tracker.duration = XmlUtils.readLongAttribute(parser, TIME_ATTR, 0);
112ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn        XmlUtils.skipCurrentTag(parser);
113ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn    }
114ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn
11553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static void loadChooserCounts(
11653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            XmlPullParser parser, UsageStats usageStats, String action)
11753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            throws XmlPullParserException, IOException {
11853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        if (action == null) {
11953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            return;
12053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
12153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        if (usageStats.mChooserCounts == null) {
12253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            usageStats.mChooserCounts = new ArrayMap<>();
12353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
12453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        if (!usageStats.mChooserCounts.containsKey(action)) {
12553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            ArrayMap<String, Integer> counts = new ArrayMap<>();
12653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            usageStats.mChooserCounts.put(action, counts);
12753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
12853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li
12953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        int eventCode;
13053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT) {
13153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            final String tag = parser.getName();
13253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (eventCode == XmlPullParser.END_TAG && tag.equals(CHOOSER_COUNT_TAG)) {
13353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                break;
13453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
13553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (eventCode != XmlPullParser.START_TAG) {
13653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                continue;
13753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
13853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (tag.equals(CATEGORY_TAG)) {
13953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                String category = XmlUtils.readStringAttribute(parser, NAME);
14053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                int count = XmlUtils.readIntAttribute(parser, COUNT);
14153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                usageStats.mChooserCounts.get(action).put(category, count);
14253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
14353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
1443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void loadConfigStats(XmlPullParser parser, IntervalStats statsOut)
1473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
1487f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        final Configuration config = new Configuration();
1497f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        Configuration.readXmlAttrs(parser, config);
1507f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
15137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final ConfigurationStats configStats = statsOut.getOrCreateConfigurationStats(config);
15237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
15337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        // Apply the offset to the beginTime to find the absolute time.
15437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        configStats.mLastTimeActive = statsOut.beginTime + XmlUtils.readLongAttribute(
15537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski                parser, LAST_TIME_ACTIVE_ATTR);
15637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
1577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        configStats.mTotalTimeActive = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
1587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        configStats.mActivationCount = XmlUtils.readIntAttribute(parser, COUNT_ATTR);
1597f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (XmlUtils.readBooleanAttribute(parser, ACTIVE_ATTR)) {
1607f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            statsOut.activeConfiguration = configStats.mConfiguration;
1613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    }
1633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void loadEvent(XmlPullParser parser, IntervalStats statsOut)
1657f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            throws XmlPullParserException, IOException {
16637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final String packageName = XmlUtils.readStringAttribute(parser, PACKAGE_ATTR);
1679d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        if (packageName == null) {
16837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
1693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
17037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final String className = XmlUtils.readStringAttribute(parser, CLASS_ATTR);
1717f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
17237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final UsageEvents.Event event = statsOut.buildEvent(packageName, className);
17337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
174ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki        event.mFlags = XmlUtils.readIntAttribute(parser, FLAGS_ATTR, 0);
175ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki
17637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        // Apply the offset to the beginTime to find the absolute time of this event.
17737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        event.mTimeStamp = statsOut.beginTime + XmlUtils.readLongAttribute(parser, TIME_ATTR);
17837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
17937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR);
180ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki        switch (event.mEventType) {
181ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki            case UsageEvents.Event.CONFIGURATION_CHANGE:
182ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                event.mConfiguration = new Configuration();
183ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                Configuration.readXmlAttrs(parser, event.mConfiguration);
184ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                break;
185ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki            case UsageEvents.Event.SHORTCUT_INVOCATION:
186ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                final String id = XmlUtils.readStringAttribute(parser, SHORTCUT_ID_ATTR);
187ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                event.mShortcutId = (id != null) ? id.intern() : null;
188ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                break;
189bfc4bf5febe3d97d3f51206c9ead2f7d2b05e700Amith Yamasani            case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
190119be9a5fc4033eba570ec94b94862401ee84570Amith Yamasani                event.mBucketAndReason = XmlUtils.readIntAttribute(parser, STANDBY_BUCKET_ATTR, 0);
191bfc4bf5febe3d97d3f51206c9ead2f7d2b05e700Amith Yamasani                break;
1927f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1937f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1947f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (statsOut.events == null) {
19560aa35b756707a16d310c222a36edbcef9d56ed4Suprabh Shukla            statsOut.events = new EventList();
1967f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
19760aa35b756707a16d310c222a36edbcef9d56ed4Suprabh Shukla        statsOut.events.insert(event);
1983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
20037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static void writeUsageStats(XmlSerializer xml, final IntervalStats stats,
20137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            final UsageStats usageStats) throws IOException {
2027f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.startTag(null, PACKAGE_TAG);
20337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
20437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        // Write the time offset.
20537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
20637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski                usageStats.mLastTimeUsed - stats.beginTime);
20737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
20837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
20937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
21037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent);
211bc813eb26e3027856114a26312e36e4bad86bd86Amith Yamasani        if (usageStats.mAppLaunchCount > 0) {
212bc813eb26e3027856114a26312e36e4bad86bd86Amith Yamasani            XmlUtils.writeIntAttribute(xml, APP_LAUNCH_COUNT_ATTR, usageStats.mAppLaunchCount);
213bc813eb26e3027856114a26312e36e4bad86bd86Amith Yamasani        }
21453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        writeChooserCounts(xml, usageStats);
2157f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.endTag(null, PACKAGE_TAG);
2167f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    }
2177f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
218ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn    private static void writeCountAndTime(XmlSerializer xml, String tag, int count, long time)
219ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn            throws IOException {
220ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn        xml.startTag(null, tag);
221ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn        XmlUtils.writeIntAttribute(xml, COUNT_ATTR, count);
222ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn        XmlUtils.writeLongAttribute(xml, TIME_ATTR, time);
223ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn        xml.endTag(null, tag);
224ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn    }
225ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn
22653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static void writeChooserCounts(XmlSerializer xml, final UsageStats usageStats)
22753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            throws IOException {
22853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        if (usageStats == null || usageStats.mChooserCounts == null ||
22953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                usageStats.mChooserCounts.keySet().isEmpty()) {
23053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            return;
23153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
23253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        final int chooserCountSize = usageStats.mChooserCounts.size();
23353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        for (int i = 0; i < chooserCountSize; i++) {
23453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            final String action = usageStats.mChooserCounts.keyAt(i);
23553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
23653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (action == null || counts == null || counts.isEmpty()) {
23753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                continue;
23853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
23953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            xml.startTag(null, CHOOSER_COUNT_TAG);
24053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            XmlUtils.writeStringAttribute(xml, NAME, action);
24153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            writeCountsForAction(xml, counts);
24253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            xml.endTag(null, CHOOSER_COUNT_TAG);
24353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
24453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    }
24553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li
24653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    private static void writeCountsForAction(XmlSerializer xml, ArrayMap<String, Integer> counts)
24753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            throws IOException {
24853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        final int countsSize = counts.size();
24953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        for (int i = 0; i < countsSize; i++) {
25053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            String key = counts.keyAt(i);
25153b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            int count = counts.valueAt(i);
25253b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            if (count > 0) {
25353b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                xml.startTag(null, CATEGORY_TAG);
25453b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                XmlUtils.writeStringAttribute(xml, NAME, key);
25553b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                XmlUtils.writeIntAttribute(xml, COUNT, count);
25653b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li                xml.endTag(null, CATEGORY_TAG);
25753b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li            }
25853b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li        }
25953b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li    }
26053b4314ad9b43b1890cbd765b896ccb0f005fdebKang Li
26137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static void writeConfigStats(XmlSerializer xml, final IntervalStats stats,
26237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            final ConfigurationStats configStats, boolean isActive) throws IOException {
26337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.startTag(null, CONFIG_TAG);
26437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
26537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        // Write the time offset.
26637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
26737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski                configStats.mLastTimeActive - stats.beginTime);
26837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
26937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, configStats.mTotalTimeActive);
27037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeIntAttribute(xml, COUNT_ATTR, configStats.mActivationCount);
2717f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (isActive) {
2727f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            XmlUtils.writeBooleanAttribute(xml, ACTIVE_ATTR, true);
2737f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
2747f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
2757f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        // Now write the attributes representing the configuration object.
27637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        Configuration.writeXmlAttrs(xml, configStats.mConfiguration);
2777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
27837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.endTag(null, CONFIG_TAG);
2793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
2803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
28137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    private static void writeEvent(XmlSerializer xml, final IntervalStats stats,
28237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            final UsageEvents.Event event) throws IOException {
28337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.startTag(null, EVENT_TAG);
28437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
28537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        // Store the time offset.
28637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeLongAttribute(xml, TIME_ATTR, event.mTimeStamp - stats.beginTime);
28737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski
2887f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, event.mPackage);
2899d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        if (event.mClass != null) {
2907f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass);
2917f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
292ad623015a119efe9b63f594af9c4703f40a0c27bMakoto Onuki        XmlUtils.writeIntAttribute(xml, FLAGS_ATTR, event.mFlags);
2937f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType);
2947f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
295ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki        switch (event.mEventType) {
296ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki            case UsageEvents.Event.CONFIGURATION_CHANGE:
297ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                if (event.mConfiguration != null) {
298ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                    Configuration.writeXmlAttrs(xml, event.mConfiguration);
299ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                }
300ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                break;
301ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki            case UsageEvents.Event.SHORTCUT_INVOCATION:
302ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                if (event.mShortcutId != null) {
303ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                    XmlUtils.writeStringAttribute(xml, SHORTCUT_ID_ATTR, event.mShortcutId);
304ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                }
305ac042501c816fa9a65aed005060ebdcfc0a0f3b2Makoto Onuki                break;
306bfc4bf5febe3d97d3f51206c9ead2f7d2b05e700Amith Yamasani            case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
307119be9a5fc4033eba570ec94b94862401ee84570Amith Yamasani                if (event.mBucketAndReason != 0) {
308119be9a5fc4033eba570ec94b94862401ee84570Amith Yamasani                    XmlUtils.writeIntAttribute(xml, STANDBY_BUCKET_ATTR, event.mBucketAndReason);
309bfc4bf5febe3d97d3f51206c9ead2f7d2b05e700Amith Yamasani                }
3109d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        }
3117f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
31237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.endTag(null, EVENT_TAG);
3133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
3143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
3153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    /**
3163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * Reads from the {@link XmlPullParser}, assuming that it is already on the
3173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * <code><usagestats></code> tag.
3183516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     *
3193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param parser The parser from which to read events.
3203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param statsOut The stats object to populate with the data from the XML file.
3213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     */
3223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    public static void read(XmlPullParser parser, IntervalStats statsOut)
3233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
32437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        statsOut.packageStats.clear();
3257f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        statsOut.configurations.clear();
3267f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        statsOut.activeConfiguration = null;
3273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
3283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (statsOut.events != null) {
3293516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            statsOut.events.clear();
3303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
3313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
332690f78adf1737b2356d341b46f21a4e2d5df58ebEdward Cunningham        statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
3333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
3347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        int eventCode;
3357f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        int outerDepth = parser.getDepth();
3367f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT
3377f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                && (eventCode != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3387f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            if (eventCode != XmlPullParser.START_TAG) {
3397f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                continue;
3407f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            }
3417f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
3427f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            final String tag = parser.getName();
3437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            switch (tag) {
3443378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                case INTERACTIVE_TAG:
3453378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    loadCountAndTime(parser, statsOut.interactiveTracker);
3463378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    break;
3473378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn
3483378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                case NON_INTERACTIVE_TAG:
3493378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    loadCountAndTime(parser, statsOut.nonInteractiveTracker);
3503378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    break;
3513378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn
3523378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                case KEYGUARD_SHOWN_TAG:
3533378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    loadCountAndTime(parser, statsOut.keyguardShownTracker);
3543378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    break;
3553378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn
3563378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                case KEYGUARD_HIDDEN_TAG:
3573378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    loadCountAndTime(parser, statsOut.keyguardHiddenTracker);
3583378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                    break;
359ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn
3607f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                case PACKAGE_TAG:
3617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    loadUsageStats(parser, statsOut);
3627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    break;
3633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
36437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski                case CONFIG_TAG:
3657f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    loadConfigStats(parser, statsOut);
3667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    break;
3677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
36837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski                case EVENT_TAG:
3697f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    loadEvent(parser, statsOut);
3707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    break;
3713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
3723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
3733516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
3743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
3753516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    /**
37637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski     * Writes the stats object to an XML file. The {@link XmlSerializer}
3773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * has already written the <code><usagestats></code> tag, but attributes may still
3783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * be added.
3793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     *
38037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski     * @param xml The serializer to which to write the packageStats data.
3813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param stats The stats object to write to the XML file.
3823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     */
38337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski    public static void write(XmlSerializer xml, IntervalStats stats) throws IOException {
38437a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime);
3853516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
3863378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn        writeCountAndTime(xml, INTERACTIVE_TAG, stats.interactiveTracker.count,
3873378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                stats.interactiveTracker.duration);
3883378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn        writeCountAndTime(xml, NON_INTERACTIVE_TAG, stats.nonInteractiveTracker.count,
3893378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                stats.nonInteractiveTracker.duration);
3903378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn        writeCountAndTime(xml, KEYGUARD_SHOWN_TAG, stats.keyguardShownTracker.count,
3913378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                stats.keyguardShownTracker.duration);
3923378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn        writeCountAndTime(xml, KEYGUARD_HIDDEN_TAG, stats.keyguardHiddenTracker.count,
3933378aa9f88101d77bc52c1a00b257c752bd8c193Dianne Hackborn                stats.keyguardHiddenTracker.duration);
394ced54398cc0dfd2f782153560c2ffd0eb8743045Dianne Hackborn
39537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.startTag(null, PACKAGES_TAG);
39637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        final int statsCount = stats.packageStats.size();
3973516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        for (int i = 0; i < statsCount; i++) {
39837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            writeUsageStats(xml, stats, stats.packageStats.valueAt(i));
3993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
40037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.endTag(null, PACKAGES_TAG);
4013516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
40237a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.startTag(null, CONFIGURATIONS_TAG);
4037f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        final int configCount = stats.configurations.size();
4047f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        for (int i = 0; i < configCount; i++) {
4057f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i));
40637a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski            writeConfigStats(xml, stats, stats.configurations.valueAt(i), active);
4077f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
40837a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.endTag(null, CONFIGURATIONS_TAG);
4097f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
41037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.startTag(null, EVENT_LOG_TAG);
4117f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        final int eventCount = stats.events != null ? stats.events.size() : 0;
4127f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        for (int i = 0; i < eventCount; i++) {
41360aa35b756707a16d310c222a36edbcef9d56ed4Suprabh Shukla            writeEvent(xml, stats, stats.events.get(i));
4143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
41537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski        xml.endTag(null, EVENT_LOG_TAG);
4163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
4173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
4183516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private UsageStatsXmlV1() {
4193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
4203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski}
421