XmlUtil.java revision 052b948a8b8a009486e35cb56dbd7bb9516e8626
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi.util;
18
19import android.net.IpConfiguration;
20import android.net.IpConfiguration.IpAssignment;
21import android.net.IpConfiguration.ProxySettings;
22import android.net.LinkAddress;
23import android.net.NetworkUtils;
24import android.net.ProxyInfo;
25import android.net.RouteInfo;
26import android.net.StaticIpConfiguration;
27import android.net.wifi.WifiConfiguration;
28import android.util.Log;
29
30import com.android.internal.util.XmlUtils;
31
32import org.xmlpull.v1.XmlPullParser;
33import org.xmlpull.v1.XmlPullParserException;
34import org.xmlpull.v1.XmlSerializer;
35
36import java.io.IOException;
37import java.net.Inet4Address;
38import java.net.InetAddress;
39import java.util.BitSet;
40
41/**
42 * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core.
43 * The utility provides methods to write/parse section headers and write/parse values.
44 * This utility is designed for formatting the XML into the following format:
45 * <Document Header>
46 *  <Section 1 Header>
47 *   <Value 1>
48 *   <Value 2>
49 *   ...
50 *   <Sub Section 1 Header>
51 *    <Value 1>
52 *    <Value 2>
53 *    ...
54 *   </Sub Section 1 Header>
55 *  </Section 1 Header>
56 * </Document Header>
57 */
58public class XmlUtil {
59    private static final String TAG = "WifiXmlUtil";
60
61    /**
62     * Ensure that the XML stream is at a start tag or the end of document.
63     *
64     * @throws XmlPullParserException if parsing errors occur.
65     */
66    private static void gotoStartTag(XmlPullParser in)
67            throws XmlPullParserException, IOException {
68        int type = in.getEventType();
69        while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
70            type = in.next();
71        }
72    }
73
74    /**
75     * Ensure that the XML stream is at an end tag or the end of document.
76     *
77     * @throws XmlPullParserException if parsing errors occur.
78     */
79    private static void gotoEndTag(XmlPullParser in)
80            throws XmlPullParserException, IOException {
81        int type = in.getEventType();
82        while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) {
83            type = in.next();
84        }
85    }
86
87    /**
88     * Start processing the XML stream at the document header.
89     *
90     * @param in         XmlPullParser instance pointing to the XML stream.
91     * @param headerName expected name for the start tag.
92     * @throws XmlPullParserException if parsing errors occur.
93     */
94    public static void gotoDocumentStart(XmlPullParser in, String headerName)
95            throws XmlPullParserException, IOException {
96        XmlUtils.beginDocument(in, headerName);
97    }
98
99    /**
100     * Move the XML stream to the next section header. The provided outerDepth is used to find
101     * sub sections within that depth.
102     *
103     * @param in         XmlPullParser instance pointing to the XML stream.
104     * @param headerName expected name for the start tag.
105     * @param outerDepth Find section within this depth.
106     * @return {@code true} if a start tag with the provided name is found, {@code false} otherwise
107     * @throws XmlPullParserException if parsing errors occur.
108     */
109    public static boolean gotoNextSection(XmlPullParser in, String headerName, int outerDepth)
110            throws XmlPullParserException, IOException {
111        while (XmlUtils.nextElementWithin(in, outerDepth)) {
112            if (in.getName().equals(headerName)) {
113                return true;
114            }
115        }
116        return false;
117    }
118
119    /**
120     * Checks if the stream is at the end of a section of values. This moves the stream to next tag
121     * and checks if it finds an end tag at the specified depth.
122     *
123     * @param in           XmlPullParser instance pointing to the XML stream.
124     * @param sectionDepth depth of the start tag of this section. Used to match the end tag.
125     * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise
126     * @throws XmlPullParserException if parsing errors occur.
127     */
128    public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth)
129            throws XmlPullParserException, IOException {
130        return (in.nextTag() == XmlPullParser.END_TAG && in.getDepth() == sectionDepth);
131    }
132
133    /**
134     * Read the current value in the XML stream using core XmlUtils and stores the retrieved
135     * value name in the string provided. This method reads the value contained in current start
136     * tag.
137     * Note: Because there could be genuine null values being read from the XML, this method raises
138     * an exception to indicate errors.
139     *
140     * @param in        XmlPullParser instance pointing to the XML stream.
141     * @param valueName An array of one string, used to return the name attribute
142     *                  of the value's tag.
143     * @return value retrieved from the XML stream.
144     * @throws XmlPullParserException if parsing errors occur.
145     */
146    public static Object readCurrentValue(XmlPullParser in, String[] valueName)
147            throws XmlPullParserException, IOException {
148        Object value = XmlUtils.readValueXml(in, valueName);
149        // XmlUtils.readValue does not always move the stream to the end of the tag. So, move
150        // it to the end tag before returning from here.
151        gotoEndTag(in);
152        return value;
153    }
154
155    /**
156     * Read the next value in the XML stream using core XmlUtils and ensure that it matches the
157     * provided name. This method moves the stream to the next start tag and reads the value
158     * contained in it.
159     * Note: Because there could be genuine null values being read from the XML, this method raises
160     * an exception to indicate errors.
161     *
162     * @param in XmlPullParser instance pointing to the XML stream.
163     * @return value retrieved from the XML stream.
164     * @throws XmlPullParserException if the value read does not match |expectedName|,
165     *                                or if parsing errors occur.
166     */
167    public static Object readNextValueWithName(XmlPullParser in, String expectedName)
168            throws XmlPullParserException, IOException {
169        String[] valueName = new String[1];
170        XmlUtils.nextElement(in);
171        Object value = readCurrentValue(in, valueName);
172        if (valueName[0].equals(expectedName)) {
173            return value;
174        }
175        throw new XmlPullParserException(
176                "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]);
177    }
178
179    /**
180     * Write the XML document start with the provided document header name.
181     *
182     * @param out        XmlSerializer instance pointing to the XML stream.
183     * @param headerName name for the start tag.
184     */
185    public static void writeDocumentStart(XmlSerializer out, String headerName)
186            throws IOException {
187        out.startDocument(null, true);
188        out.startTag(null, headerName);
189    }
190
191    /**
192     * Write the XML document end with the provided document header name.
193     *
194     * @param out        XmlSerializer instance pointing to the XML stream.
195     * @param headerName name for the end tag.
196     */
197    public static void writeDocumentEnd(XmlSerializer out, String headerName)
198            throws IOException {
199        out.endTag(null, headerName);
200        out.endDocument();
201    }
202
203    /**
204     * Write a section start header tag with the provided section name.
205     *
206     * @param out        XmlSerializer instance pointing to the XML stream.
207     * @param headerName name for the start tag.
208     */
209    public static void writeNextSectionStart(XmlSerializer out, String headerName)
210            throws IOException {
211        out.startTag(null, headerName);
212    }
213
214    /**
215     * Write a section end header tag with the provided section name.
216     *
217     * @param out        XmlSerializer instance pointing to the XML stream.
218     * @param headerName name for the end tag.
219     */
220    public static void writeNextSectionEnd(XmlSerializer out, String headerName)
221            throws IOException {
222        out.endTag(null, headerName);
223    }
224
225    /**
226     * Write the value with the provided name in the XML stream using core XmlUtils.
227     *
228     * @param out   XmlSerializer instance pointing to the XML stream.
229     * @param name  name of the value.
230     * @param value value to be written.
231     */
232    public static void writeNextValue(XmlSerializer out, String name, Object value)
233            throws XmlPullParserException, IOException {
234        XmlUtils.writeValueXml(value, name, out);
235    }
236
237    /**
238     * Utility class to serialize and deseriaize WifConfiguration object to XML & vice versa.
239     * This is used by both #com.android.server.wifi.WifiConfigStore &
240     * #com.android.server.wifi.WifiBackupRestore modules.
241     * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store.
242     * There is only 1 version of |parseXmlToConfiguration| for both backup & config store.
243     * The parse method is written so that any element added/deleted in future revisions can
244     * be easily handled.
245     */
246    public static class WifiConfigurationXmlUtil {
247        /**
248         * List of XML tags corresponding to WifiConfiguration object elements.
249         */
250        public static final String XML_TAG_SSID = "SSID";
251        public static final String XML_TAG_BSSID = "BSSID";
252        public static final String XML_TAG_CONFIG_KEY = "ConfigKey";
253        public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
254        public static final String XML_TAG_WEP_KEYS = "WEPKeys";
255        public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex";
256        public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
257        public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
258        public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols";
259        public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos";
260        public static final String XML_TAG_SHARED = "Shared";
261        public static final String XML_TAG_CREATOR_UID = "CreatorUid";
262
263        /**
264         * Write WepKeys to the XML stream.
265         * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements
266         * are null. XmlUtils serialization doesn't handle this array of nulls well .
267         * So, write null if the keys are not initialized.
268         */
269        private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys)
270                throws XmlPullParserException, IOException {
271            if (wepKeys[0] != null) {
272                XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeys);
273            } else {
274                XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null);
275            }
276        }
277
278        /**
279         * Write the Configuration data elements that are common for backup & config store to the
280         * XML stream.
281         *
282         * @param out           XmlSerializer instance pointing to the XML stream.
283         * @param configuration WifiConfiguration object to be serialized.
284         */
285        public static void writeCommonWifiConfigurationElementsToXml(XmlSerializer out,
286                WifiConfiguration configuration)
287                throws XmlPullParserException, IOException {
288            XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.configKey());
289            XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID);
290            XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID);
291            XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, configuration.preSharedKey);
292            writeWepKeysToXml(out, configuration.wepKeys);
293            XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex);
294            XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID);
295            XmlUtil.writeNextValue(
296                    out, XML_TAG_ALLOWED_KEY_MGMT,
297                    configuration.allowedKeyManagement.toByteArray());
298            XmlUtil.writeNextValue(
299                    out, XML_TAG_ALLOWED_PROTOCOLS,
300                    configuration.allowedProtocols.toByteArray());
301            XmlUtil.writeNextValue(
302                    out, XML_TAG_ALLOWED_AUTH_ALGOS,
303                    configuration.allowedAuthAlgorithms.toByteArray());
304            XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared);
305            XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid);
306        }
307
308        /**
309         * Write the Configuration data elements for backup from the provided Configuration to the
310         * XML stream.
311         * Note: This is a subset of the elements serialized for config store.
312         *
313         * @param out           XmlSerializer instance pointing to the XML stream.
314         * @param configuration WifiConfiguration object to be serialized.
315         */
316        public static void writeWifiConfigurationToXmlForBackup(XmlSerializer out,
317                WifiConfiguration configuration)
318                throws XmlPullParserException, IOException {
319            writeCommonWifiConfigurationElementsToXml(out, configuration);
320        }
321
322        /**
323         * Write the Configuration data elements for config store from the provided Configuration
324         * to the XML stream.
325         */
326        public static void writeWifiConfigurationToXmlForConfigStore(XmlSerializer out,
327                WifiConfiguration configuration)
328                throws XmlPullParserException, IOException {
329            writeCommonWifiConfigurationElementsToXml(out, configuration);
330            // TODO: Will need to add more elements which needs to be persisted.
331        }
332
333        /**
334         * Populate wepKeys array only if they were non-null in the backup data.
335         */
336        private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys)
337                throws XmlPullParserException, IOException {
338            String[] wepKeysInData = (String[]) value;
339            if (wepKeysInData != null) {
340                for (int i = 0; i < wepKeys.length; i++) {
341                    wepKeys[i] = wepKeysInData[i];
342                }
343            }
344        }
345
346        /**
347         * Parses the configuration data elements from the provided XML stream to a Configuration.
348         * Note: This is used for parsing both backup data and config store data. Looping through
349         * the tags make it easy to add or remove elements in the future versions if needed.
350         *
351         * @param in            XmlPullParser instance pointing to the XML stream.
352         * @param outerTagDepth depth of the outer tag in the XML document.
353         * @return WifiConfiguration object if parsing is successful, null otherwise.
354         */
355        public static WifiConfiguration parseWifiConfigurationFromXml(XmlPullParser in,
356                int outerTagDepth)
357                throws XmlPullParserException, IOException {
358            WifiConfiguration configuration = new WifiConfiguration();
359            String configKeyInData = null;
360
361            // Loop through and parse out all the elements from the stream within this section.
362            while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
363                String[] valueName = new String[1];
364                Object value = XmlUtil.readCurrentValue(in, valueName);
365                if (valueName[0] == null) {
366                    Log.e(TAG, "Missing value name");
367                    return null;
368                }
369                switch (valueName[0]) {
370                    case XML_TAG_CONFIG_KEY:
371                        configKeyInData = (String) value;
372                        break;
373                    case XML_TAG_SSID:
374                        configuration.SSID = (String) value;
375                        break;
376                    case XML_TAG_BSSID:
377                        configuration.BSSID = (String) value;
378                        break;
379                    case XML_TAG_PRE_SHARED_KEY:
380                        configuration.preSharedKey = (String) value;
381                        break;
382                    case XML_TAG_WEP_KEYS:
383                        populateWepKeysFromXmlValue(value, configuration.wepKeys);
384                        break;
385                    case XML_TAG_WEP_TX_KEY_INDEX:
386                        configuration.wepTxKeyIndex = (int) value;
387                        break;
388                    case XML_TAG_HIDDEN_SSID:
389                        configuration.hiddenSSID = (boolean) value;
390                        break;
391                    case XML_TAG_ALLOWED_KEY_MGMT:
392                        byte[] allowedKeyMgmt = (byte[]) value;
393                        configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
394                        break;
395                    case XML_TAG_ALLOWED_PROTOCOLS:
396                        byte[] allowedProtocols = (byte[]) value;
397                        configuration.allowedProtocols = BitSet.valueOf(allowedProtocols);
398                        break;
399                    case XML_TAG_ALLOWED_AUTH_ALGOS:
400                        byte[] allowedAuthAlgorithms = (byte[]) value;
401                        configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms);
402                        break;
403                    case XML_TAG_SHARED:
404                        configuration.shared = (boolean) value;
405                        break;
406                    case XML_TAG_CREATOR_UID:
407                        configuration.creatorUid = (int) value;
408                        break;
409                    default:
410                        Log.e(TAG, "Unknown value name found: " + valueName[0]);
411                        return null;
412                }
413            }
414            // We should now have all the data to calculate the configKey. Compare it against the
415            // configKey stored in the XML data.
416            String configKeyCalculated = configuration.configKey();
417            if (configKeyInData == null || !configKeyInData.equals(configKeyCalculated)) {
418                Log.e(TAG, "Configuration key does not match. Retrieved: " + configKeyInData
419                        + ", Calculated: " + configKeyCalculated);
420                return null;
421            }
422            return configuration;
423        }
424    }
425
426    /**
427     * Utility class to serialize and deseriaize IpConfiguration object to XML & vice versa.
428     * This is used by both #com.android.server.wifi.WifiConfigStore &
429     * #com.android.server.wifi.WifiBackupRestore modules.
430     */
431    public static class IpConfigurationXmlUtil {
432
433        /**
434         * List of XML tags corresponding to IpConfiguration object elements.
435         */
436        public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment";
437        public static final String XML_TAG_LINK_ADDRESS = "LinkAddress";
438        public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength";
439        public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress";
440        public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers";
441        public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings";
442        public static final String XML_TAG_PROXY_HOST = "ProxyHost";
443        public static final String XML_TAG_PROXY_PORT = "ProxyPort";
444        public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac";
445        public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList";
446
447        /**
448         * Write the static IP configuration data elements to XML stream.
449         */
450        private static void writeStaticIpConfigurationToXml(XmlSerializer out,
451                StaticIpConfiguration staticIpConfiguration)
452                throws XmlPullParserException, IOException {
453            if (staticIpConfiguration.ipAddress != null) {
454                XmlUtil.writeNextValue(
455                        out, XML_TAG_LINK_ADDRESS,
456                        staticIpConfiguration.ipAddress.getAddress().getHostAddress());
457                XmlUtil.writeNextValue(
458                        out, XML_TAG_LINK_PREFIX_LENGTH,
459                        staticIpConfiguration.ipAddress.getPrefixLength());
460            } else {
461                XmlUtil.writeNextValue(
462                        out, XML_TAG_LINK_ADDRESS, null);
463                XmlUtil.writeNextValue(
464                        out, XML_TAG_LINK_PREFIX_LENGTH, null);
465            }
466            if (staticIpConfiguration.gateway != null) {
467                XmlUtil.writeNextValue(
468                        out, XML_TAG_GATEWAY_ADDRESS,
469                        staticIpConfiguration.gateway.getHostAddress());
470            } else {
471                XmlUtil.writeNextValue(
472                        out, XML_TAG_GATEWAY_ADDRESS, null);
473
474            }
475            if (staticIpConfiguration.dnsServers != null) {
476                // Create a string array of DNS server addresses
477                String[] dnsServers = new String[staticIpConfiguration.dnsServers.size()];
478                int dnsServerIdx = 0;
479                for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
480                    dnsServers[dnsServerIdx++] = inetAddr.getHostAddress();
481                }
482                XmlUtil.writeNextValue(
483                        out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers);
484            } else {
485                XmlUtil.writeNextValue(
486                        out, XML_TAG_DNS_SERVER_ADDRESSES, null);
487            }
488        }
489
490        /**
491         * Write the IP configuration data elements from the provided Configuration to the XML
492         * stream.
493         */
494        public static void writeIpConfigurationToXml(XmlSerializer out,
495                IpConfiguration ipConfiguration)
496                throws XmlPullParserException, IOException {
497            // Write IP assignment settings
498            XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT,
499                    ipConfiguration.ipAssignment.toString());
500            switch (ipConfiguration.ipAssignment) {
501                case STATIC:
502                    writeStaticIpConfigurationToXml(
503                            out, ipConfiguration.getStaticIpConfiguration());
504                    break;
505                default:
506                    break;
507            }
508
509            // Write proxy settings
510            XmlUtil.writeNextValue(
511                    out, XML_TAG_PROXY_SETTINGS,
512                    ipConfiguration.proxySettings.toString());
513            switch (ipConfiguration.proxySettings) {
514                case STATIC:
515                    XmlUtil.writeNextValue(
516                            out, XML_TAG_PROXY_HOST,
517                            ipConfiguration.httpProxy.getHost());
518                    XmlUtil.writeNextValue(
519                            out, XML_TAG_PROXY_PORT,
520                            ipConfiguration.httpProxy.getPort());
521                    XmlUtil.writeNextValue(
522                            out, XML_TAG_PROXY_EXCLUSION_LIST,
523                            ipConfiguration.httpProxy.getExclusionListAsString());
524                    break;
525                case PAC:
526                    XmlUtil.writeNextValue(
527                            out, XML_TAG_PROXY_PAC_FILE,
528                            ipConfiguration.httpProxy.getPacFileUrl().toString());
529                    break;
530                default:
531                    break;
532            }
533        }
534
535        /**
536         * Parse out the static IP configuration from the XML stream.
537         */
538        private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in)
539                throws XmlPullParserException, IOException {
540            StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
541
542            String linkAddressString =
543                    (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS);
544            Integer linkPrefixLength =
545                    (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH);
546            if (linkAddressString != null && linkPrefixLength != null) {
547                LinkAddress linkAddress = new LinkAddress(
548                        NetworkUtils.numericToInetAddress(linkAddressString),
549                        linkPrefixLength);
550                if (linkAddress.getAddress() instanceof Inet4Address) {
551                    staticIpConfiguration.ipAddress = linkAddress;
552                } else {
553                    Log.w(TAG, "Non-IPv4 address: " + linkAddress);
554                }
555            }
556            String gatewayAddressString =
557                    (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS);
558            if (gatewayAddressString != null) {
559                LinkAddress dest = null;
560                InetAddress gateway =
561                        NetworkUtils.numericToInetAddress(gatewayAddressString);
562                RouteInfo route = new RouteInfo(dest, gateway);
563                if (route.isIPv4Default()) {
564                    staticIpConfiguration.gateway = gateway;
565                } else {
566                    Log.w(TAG, "Non-IPv4 default route: " + route);
567                }
568            }
569            String[] dnsServerAddressesString =
570                    (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES);
571            if (dnsServerAddressesString != null) {
572                for (String dnsServerAddressString : dnsServerAddressesString) {
573                    InetAddress dnsServerAddress =
574                            NetworkUtils.numericToInetAddress(dnsServerAddressString);
575                    staticIpConfiguration.dnsServers.add(dnsServerAddress);
576                }
577            }
578            return staticIpConfiguration;
579        }
580
581        /**
582         * Parses the IP configuration data elements from the provided XML stream to a
583         * IpConfiguration.
584         *
585         * @param in            XmlPullParser instance pointing to the XML stream.
586         * @param outerTagDepth depth of the outer tag in the XML document.
587         * @return IpConfiguration object if parsing is successful, null otherwise.
588         */
589        public static IpConfiguration parseIpConfigurationFromXml(XmlPullParser in,
590                int outerTagDepth)
591                throws XmlPullParserException, IOException {
592            IpConfiguration ipConfiguration = new IpConfiguration();
593
594            // Parse out the IP assignment info first.
595            String ipAssignmentString =
596                    (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT);
597            IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString);
598            ipConfiguration.setIpAssignment(ipAssignment);
599            switch (ipAssignment) {
600                case STATIC:
601                    ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in));
602                    break;
603                case DHCP:
604                case UNASSIGNED:
605                    break;
606                default:
607                    Log.wtf(TAG, "Unknown ip assignment type: " + ipAssignment);
608                    return null;
609            }
610
611            // Parse out the proxy settings next.
612            String proxySettingsString =
613                    (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS);
614            ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString);
615            ipConfiguration.setProxySettings(proxySettings);
616            switch (proxySettings) {
617                case STATIC:
618                    String proxyHost =
619                            (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST);
620                    int proxyPort =
621                            (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT);
622                    String proxyExclusionList =
623                            (String) XmlUtil.readNextValueWithName(
624                                    in, XML_TAG_PROXY_EXCLUSION_LIST);
625                    ipConfiguration.setHttpProxy(
626                            new ProxyInfo(proxyHost, proxyPort, proxyExclusionList));
627                    break;
628                case PAC:
629                    String proxyPacFile =
630                            (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE);
631                    ipConfiguration.setHttpProxy(new ProxyInfo(proxyPacFile));
632                    break;
633                case NONE:
634                case UNASSIGNED:
635                    break;
636                default:
637                    Log.wtf(TAG, "Unknown proxy settings type: " + proxySettings);
638                    return null;
639            }
640            return ipConfiguration;
641        }
642    }
643}
644
645