UsageStatsXmlV1.java revision 7f61e96db7c90c1f4418359672aa4656aebee500
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.FastXmlSerializer;
193516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport com.android.internal.util.XmlUtils;
203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
213516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.xmlpull.v1.XmlPullParser;
223516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException;
237f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport org.xmlpull.v1.XmlSerializer;
243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
257f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.app.usage.ConfigurationStats;
263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.TimeSparseArray;
273516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents;
283516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageStats;
293516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.content.ComponentName;
307f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.content.res.Configuration;
313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
323516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.io.IOException;
333516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.net.ProtocolException;
347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport java.util.Locale;
353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/**
373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * UsageStats reader/writer for version 1 of the XML format.
383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */
393516800b611a79339a3c188332d13a26e9086b09Adam Lesinskifinal class UsageStatsXmlV1 {
407f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String PACKAGE_TAG = "package";
417f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String CONFIGURATION_TAG = "config";
427f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String EVENT_LOG_TAG = "event-log";
437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String BEGIN_TIME_ATTR = "beginTime";
453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String END_TIME_ATTR = "endTime";
463516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String NAME_ATTR = "name";
479d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski    private static final String PACKAGE_ATTR = "package";
489d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski    private static final String CLASS_ATTR = "class";
493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TOTAL_TIME_ACTIVE_ATTR = "totalTimeActive";
503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
517f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String COUNT_ATTR = "count";
527f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static final String ACTIVE_ATTR = "active";
533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String LAST_EVENT_ATTR = "lastEvent";
543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TYPE_ATTR = "type";
553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final String TIME_ATTR = "time";
563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut)
583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        final String name = parser.getAttributeValue(null, NAME_ATTR);
603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (name == null) {
613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throw new ProtocolException("no " + NAME_ATTR + " attribute present");
623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        UsageStats stats = statsOut.getOrCreateUsageStats(name);
653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mLastTimeUsed = XmlUtils.readLongAttribute(parser, LAST_TIME_ACTIVE_ATTR);
673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
683516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void loadConfigStats(XmlPullParser parser, IntervalStats statsOut)
713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
727f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        final Configuration config = new Configuration();
737f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        Configuration.readXmlAttrs(parser, config);
747f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
757f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        ConfigurationStats configStats = statsOut.getOrCreateConfigurationStats(config);
767f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        configStats.mLastTimeActive = XmlUtils.readLongAttribute(parser, LAST_TIME_ACTIVE_ATTR);
777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        configStats.mTotalTimeActive = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
787f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        configStats.mActivationCount = XmlUtils.readIntAttribute(parser, COUNT_ATTR);
797f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (XmlUtils.readBooleanAttribute(parser, ACTIVE_ATTR)) {
807f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            statsOut.activeConfiguration = configStats.mConfiguration;
813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
827f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    }
833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
847f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void loadEvent(XmlPullParser parser, IntervalStats statsOut)
857f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            throws XmlPullParserException, IOException {
869d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        String packageName = XmlUtils.readStringAttribute(parser, PACKAGE_ATTR);
879d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        String className;
889d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        if (packageName == null) {
899d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            // Try getting the component name if it exists.
909d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            final String componentName = XmlUtils.readStringAttribute(parser, NAME_ATTR);
919d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            if (componentName == null) {
929d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski                throw new ProtocolException("no " + NAME_ATTR + " or " + PACKAGE_ATTR +
939d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski                        " attribute present");
949d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            }
959d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            ComponentName component = ComponentName.unflattenFromString(componentName);
969d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            if (component == null) {
979d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski                throw new ProtocolException("ComponentName " + componentName + " is invalid");
989d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            }
999d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski
1009d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            packageName = component.getPackageName();
1019d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            className = component.getClassName();
1029d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        } else {
1039d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski            className = XmlUtils.readStringAttribute(parser, CLASS_ATTR);
1043516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1053516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1069d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        UsageEvents.Event event = statsOut.buildEvent(packageName, className);
1073516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR);
1083516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        event.mTimeStamp = XmlUtils.readLongAttribute(parser, TIME_ATTR);
1097f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1107f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
1117f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            event.mConfiguration = new Configuration();
1127f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            Configuration.readXmlAttrs(parser, event.mConfiguration);
1137f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1147f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1157f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (statsOut.events == null) {
1167f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            statsOut.events = new TimeSparseArray<>();
1177f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1187f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        statsOut.events.put(event.mTimeStamp, event);
1193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1217f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void writeUsageStats(XmlSerializer xml, final UsageStats stats)
1223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws IOException {
1237f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.startTag(null, PACKAGE_TAG);
1247f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeStringAttribute(xml, NAME_ATTR, stats.mPackageName);
1257f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, stats.mTotalTimeInForeground);
1267f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, stats.mLastTimeUsed);
1277f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, stats.mLastEvent);
1287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.endTag(null, PACKAGE_TAG);
1297f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    }
1307f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1317f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void writeConfigStats(XmlSerializer xml, final ConfigurationStats stats,
1327f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            boolean isActive) throws IOException {
1337f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.startTag(null, CONFIGURATION_TAG);
1347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, stats.mLastTimeActive);
1357f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, stats.mTotalTimeActive);
1367f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeIntAttribute(xml, COUNT_ATTR, stats.mActivationCount);
1377f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (isActive) {
1387f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            XmlUtils.writeBooleanAttribute(xml, ACTIVE_ATTR, true);
1397f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1407f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1417f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        // Now write the attributes representing the configuration object.
1427f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        Configuration.writeXmlAttrs(xml, stats.mConfiguration);
1437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1447f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.endTag(null, CONFIGURATION_TAG);
1453516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1463516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1477f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private static void writeEvent(XmlSerializer xml, final UsageEvents.Event event)
1483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws IOException {
1497f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.startTag(null, EVENT_LOG_TAG);
1507f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, event.mPackage);
1519d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        if (event.mClass != null) {
1527f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass);
1537f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1547f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType);
1557f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        XmlUtils.writeLongAttribute(xml, TIME_ATTR, event.mTimeStamp);
1567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE
1587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                && event.mConfiguration != null) {
1597f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            Configuration.writeXmlAttrs(xml, event.mConfiguration);
1609d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski        }
1617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        xml.endTag(null, EVENT_LOG_TAG);
1633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    /**
1663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * Reads from the {@link XmlPullParser}, assuming that it is already on the
1673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * <code><usagestats></code> tag.
1683516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     *
1693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param parser The parser from which to read events.
1703516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param statsOut The stats object to populate with the data from the XML file.
1713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     */
1723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    public static void read(XmlPullParser parser, IntervalStats statsOut)
1733516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            throws XmlPullParserException, IOException {
1743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        statsOut.stats.clear();
1757f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        statsOut.configurations.clear();
1767f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        statsOut.activeConfiguration = null;
1773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        if (statsOut.events != null) {
1793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            statsOut.events.clear();
1803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        statsOut.beginTime = XmlUtils.readLongAttribute(parser, BEGIN_TIME_ATTR);
1833516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        statsOut.endTime = XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
1843516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1857f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        int eventCode;
1867f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        int outerDepth = parser.getDepth();
1877f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT
1887f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                && (eventCode != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1897f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            if (eventCode != XmlPullParser.START_TAG) {
1907f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                continue;
1917f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            }
1927f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1937f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            final String tag = parser.getName();
1947f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            switch (tag) {
1957f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                case PACKAGE_TAG:
1967f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    loadUsageStats(parser, statsOut);
1977f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    break;
1983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1997f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                case CONFIGURATION_TAG:
2007f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    loadConfigStats(parser, statsOut);
2017f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    break;
2027f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
2037f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                case EVENT_LOG_TAG:
2047f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    loadEvent(parser, statsOut);
2057f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    break;
2063516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
2073516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
2083516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
2093516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
2103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    /**
2113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * Writes the stats object to an XML file. The {@link FastXmlSerializer}
2123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * has already written the <code><usagestats></code> tag, but attributes may still
2133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * be added.
2143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     *
2153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param serializer The serializer to which to write the stats data.
2163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     * @param stats The stats object to write to the XML file.
2173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski     */
2183516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    public static void write(FastXmlSerializer serializer, IntervalStats stats) throws IOException {
2193516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, BEGIN_TIME_ATTR, Long.toString(stats.beginTime));
2203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        serializer.attribute(null, END_TIME_ATTR, Long.toString(stats.endTime));
2213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
2223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        final int statsCount = stats.stats.size();
2233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        for (int i = 0; i < statsCount; i++) {
2243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            writeUsageStats(serializer, stats.stats.valueAt(i));
2253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
2263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
2277f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        final int configCount = stats.configurations.size();
2287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        for (int i = 0; i < configCount; i++) {
2297f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i));
2307f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            writeConfigStats(serializer, stats.configurations.valueAt(i), active);
2317f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
2327f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
2337f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        final int eventCount = stats.events != null ? stats.events.size() : 0;
2347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        for (int i = 0; i < eventCount; i++) {
2357f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            writeEvent(serializer, stats.events.valueAt(i));
2363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
2373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
2383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
2393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private UsageStatsXmlV1() {
2403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
2413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski}
242