Home | History | Annotate | Download | only in adapter
      1 /* Copyright (C) 2010 The Android Open Source Project.
      2  *
      3  * Licensed under the Apache License, Version 2.0 (the "License");
      4  * you may not use this file except in compliance with the License.
      5  * You may obtain a copy of the License at
      6  *
      7  *      http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software
     10  * distributed under the License is distributed on an "AS IS" BASIS,
     11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12  * See the License for the specific language governing permissions and
     13  * limitations under the License.
     14  */
     15 
     16 package com.android.exchange.adapter;
     17 
     18 import android.app.admin.DevicePolicyManager;
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.os.storage.StorageManager;
     22 import android.os.storage.StorageVolume;
     23 
     24 import com.android.emailcommon.provider.Policy;
     25 import com.android.exchange.EasSyncService;
     26 import com.android.exchange.R;
     27 
     28 import org.xmlpull.v1.XmlPullParser;
     29 import org.xmlpull.v1.XmlPullParserException;
     30 import org.xmlpull.v1.XmlPullParserFactory;
     31 
     32 import java.io.ByteArrayInputStream;
     33 import java.io.IOException;
     34 import java.io.InputStream;
     35 import java.util.ArrayList;
     36 
     37 /**
     38  * Parse the result of the Provision command
     39  */
     40 public class ProvisionParser extends Parser {
     41     private final EasSyncService mService;
     42     private Policy mPolicy = null;
     43     private String mSecuritySyncKey = null;
     44     private boolean mRemoteWipe = false;
     45     private boolean mIsSupportable = true;
     46     private boolean smimeRequired = false;
     47     private final Resources mResources;
     48 
     49     public ProvisionParser(InputStream in, EasSyncService service) throws IOException {
     50         super(in);
     51         mService = service;
     52         mResources = service.mContext.getResources();
     53     }
     54 
     55     public Policy getPolicy() {
     56         return mPolicy;
     57     }
     58 
     59     public String getSecuritySyncKey() {
     60         return mSecuritySyncKey;
     61     }
     62 
     63     public void setSecuritySyncKey(String securitySyncKey) {
     64         mSecuritySyncKey = securitySyncKey;
     65     }
     66 
     67     public boolean getRemoteWipe() {
     68         return mRemoteWipe;
     69     }
     70 
     71     public boolean hasSupportablePolicySet() {
     72         return (mPolicy != null) && mIsSupportable;
     73     }
     74 
     75     public void clearUnsupportablePolicies() {
     76         mIsSupportable = true;
     77         mPolicy.mProtocolPoliciesUnsupported = null;
     78     }
     79 
     80     private void addPolicyString(StringBuilder sb, int res) {
     81         sb.append(mResources.getString(res));
     82         sb.append(Policy.POLICY_STRING_DELIMITER);
     83     }
     84 
     85     /**
     86      * Complete setup of a Policy; we normalize it first (removing inconsistencies, etc.) and then
     87      * generate the tokenized "protocol policies enforced" string.  Note that unsupported policies
     88      * must have been added prior to calling this method (this is only a possibility with wbxml
     89      * policy documents, as all versions of the OS support the policies in xml documents).
     90      */
     91     private void setPolicy(Policy policy) {
     92         policy.normalize();
     93         StringBuilder sb = new StringBuilder();
     94         if (policy.mDontAllowAttachments) {
     95             addPolicyString(sb, R.string.policy_dont_allow_attachments);
     96         }
     97         if (policy.mRequireManualSyncWhenRoaming) {
     98             addPolicyString(sb, R.string.policy_require_manual_sync_roaming);
     99         }
    100         policy.mProtocolPoliciesEnforced = sb.toString();
    101         mPolicy = policy;
    102     }
    103 
    104     private boolean deviceSupportsEncryption() {
    105         DevicePolicyManager dpm = (DevicePolicyManager)
    106                 mService.mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    107         int status = dpm.getStorageEncryptionStatus();
    108         return status != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
    109     }
    110 
    111     private void parseProvisionDocWbxml() throws IOException {
    112         Policy policy = new Policy();
    113         ArrayList<Integer> unsupportedList = new ArrayList<Integer>();
    114         boolean passwordEnabled = false;
    115 
    116         while (nextTag(Tags.PROVISION_EAS_PROVISION_DOC) != END) {
    117             boolean tagIsSupported = true;
    118             int res = 0;
    119             switch (tag) {
    120                 case Tags.PROVISION_DEVICE_PASSWORD_ENABLED:
    121                     if (getValueInt() == 1) {
    122                         passwordEnabled = true;
    123                         if (policy.mPasswordMode == Policy.PASSWORD_MODE_NONE) {
    124                             policy.mPasswordMode = Policy.PASSWORD_MODE_SIMPLE;
    125                         }
    126                     }
    127                     break;
    128                 case Tags.PROVISION_MIN_DEVICE_PASSWORD_LENGTH:
    129                     policy.mPasswordMinLength = getValueInt();
    130                     break;
    131                 case Tags.PROVISION_ALPHA_DEVICE_PASSWORD_ENABLED:
    132                     if (getValueInt() == 1) {
    133                         policy.mPasswordMode = Policy.PASSWORD_MODE_STRONG;
    134                     }
    135                     break;
    136                 case Tags.PROVISION_MAX_INACTIVITY_TIME_DEVICE_LOCK:
    137                     // EAS gives us seconds, which is, happily, what the PolicySet requires
    138                     policy.mMaxScreenLockTime = getValueInt();
    139                     break;
    140                 case Tags.PROVISION_MAX_DEVICE_PASSWORD_FAILED_ATTEMPTS:
    141                     policy.mPasswordMaxFails = getValueInt();
    142                     break;
    143                 case Tags.PROVISION_DEVICE_PASSWORD_EXPIRATION:
    144                     policy.mPasswordExpirationDays = getValueInt();
    145                     break;
    146                 case Tags.PROVISION_DEVICE_PASSWORD_HISTORY:
    147                     policy.mPasswordHistory = getValueInt();
    148                     break;
    149                 case Tags.PROVISION_ALLOW_CAMERA:
    150                     policy.mDontAllowCamera = (getValueInt() == 0);
    151                     break;
    152                 case Tags.PROVISION_ALLOW_SIMPLE_DEVICE_PASSWORD:
    153                     // Ignore this unless there's any MSFT documentation for what this means
    154                     // Hint: I haven't seen any that's more specific than "simple"
    155                     getValue();
    156                     break;
    157                 // The following policies, if false, can't be supported at the moment
    158                 case Tags.PROVISION_ALLOW_STORAGE_CARD:
    159                 case Tags.PROVISION_ALLOW_UNSIGNED_APPLICATIONS:
    160                 case Tags.PROVISION_ALLOW_UNSIGNED_INSTALLATION_PACKAGES:
    161                 case Tags.PROVISION_ALLOW_WIFI:
    162                 case Tags.PROVISION_ALLOW_TEXT_MESSAGING:
    163                 case Tags.PROVISION_ALLOW_POP_IMAP_EMAIL:
    164                 case Tags.PROVISION_ALLOW_IRDA:
    165                 case Tags.PROVISION_ALLOW_HTML_EMAIL:
    166                 case Tags.PROVISION_ALLOW_BROWSER:
    167                 case Tags.PROVISION_ALLOW_CONSUMER_EMAIL:
    168                 case Tags.PROVISION_ALLOW_INTERNET_SHARING:
    169                     if (getValueInt() == 0) {
    170                         tagIsSupported = false;
    171                         switch(tag) {
    172                             case Tags.PROVISION_ALLOW_STORAGE_CARD:
    173                                 res = R.string.policy_dont_allow_storage_cards;
    174                                 break;
    175                             case Tags.PROVISION_ALLOW_UNSIGNED_APPLICATIONS:
    176                                 res = R.string.policy_dont_allow_unsigned_apps;
    177                                 break;
    178                             case Tags.PROVISION_ALLOW_UNSIGNED_INSTALLATION_PACKAGES:
    179                                 res = R.string.policy_dont_allow_unsigned_installers;
    180                                 break;
    181                             case Tags.PROVISION_ALLOW_WIFI:
    182                                 res = R.string.policy_dont_allow_wifi;
    183                                 break;
    184                             case Tags.PROVISION_ALLOW_TEXT_MESSAGING:
    185                                 res = R.string.policy_dont_allow_text_messaging;
    186                                 break;
    187                             case Tags.PROVISION_ALLOW_POP_IMAP_EMAIL:
    188                                 res = R.string.policy_dont_allow_pop_imap;
    189                                 break;
    190                             case Tags.PROVISION_ALLOW_IRDA:
    191                                 res = R.string.policy_dont_allow_irda;
    192                                 break;
    193                             case Tags.PROVISION_ALLOW_HTML_EMAIL:
    194                                 res = R.string.policy_dont_allow_html;
    195                                 policy.mDontAllowHtml = true;
    196                                 break;
    197                             case Tags.PROVISION_ALLOW_BROWSER:
    198                                 res = R.string.policy_dont_allow_browser;
    199                                 break;
    200                             case Tags.PROVISION_ALLOW_CONSUMER_EMAIL:
    201                                 res = R.string.policy_dont_allow_consumer_email;
    202                                 break;
    203                             case Tags.PROVISION_ALLOW_INTERNET_SHARING:
    204                                 res = R.string.policy_dont_allow_internet_sharing;
    205                                 break;
    206                         }
    207                         if (res > 0) {
    208                             unsupportedList.add(res);
    209                         }
    210                     }
    211                     break;
    212                 case Tags.PROVISION_ATTACHMENTS_ENABLED:
    213                     policy.mDontAllowAttachments = getValueInt() != 1;
    214                     break;
    215                 // Bluetooth: 0 = no bluetooth; 1 = only hands-free; 2 = allowed
    216                 case Tags.PROVISION_ALLOW_BLUETOOTH:
    217                     if (getValueInt() != 2) {
    218                         tagIsSupported = false;
    219                         unsupportedList.add(R.string.policy_bluetooth_restricted);
    220                     }
    221                     break;
    222                 // We may now support device (internal) encryption; we'll check this capability
    223                 // below with the call to SecurityPolicy.isSupported()
    224                 case Tags.PROVISION_REQUIRE_DEVICE_ENCRYPTION:
    225                     if (getValueInt() == 1) {
    226                          if (!deviceSupportsEncryption()) {
    227                             tagIsSupported = false;
    228                             unsupportedList.add(R.string.policy_require_encryption);
    229                         } else {
    230                             policy.mRequireEncryption = true;
    231                         }
    232                     }
    233                     break;
    234                 // Note that DEVICE_ENCRYPTION_ENABLED refers to SD card encryption, which the OS
    235                 // does not yet support.
    236                 case Tags.PROVISION_DEVICE_ENCRYPTION_ENABLED:
    237                     if (getValueInt() == 1) {
    238                         log("Policy requires SD card encryption");
    239                         // Let's see if this can be supported on our device...
    240                         if (deviceSupportsEncryption()) {
    241                             StorageManager sm = (StorageManager)mService.mContext.getSystemService(
    242                                     Context.STORAGE_SERVICE);
    243                             // NOTE: Private API!
    244                             // Go through volumes; if ANY are removable, we can't support this
    245                             // policy.
    246                             StorageVolume[] volumeList = sm.getVolumeList();
    247                             for (StorageVolume volume: volumeList) {
    248                                 if (volume.isRemovable()) {
    249                                     tagIsSupported = false;
    250                                     log("Removable: " + volume.getDescription(mService.mContext));
    251                                     break;  // Break only from the storage volume loop
    252                                 } else {
    253                                     log("Not Removable: " + volume.getDescription(mService.mContext));
    254                                 }
    255                             }
    256                             if (tagIsSupported) {
    257                                 // If this policy is requested, we MUST also require encryption
    258                                 log("Device supports SD card encryption");
    259                                 policy.mRequireEncryption = true;
    260                                 break;
    261                             }
    262                         } else {
    263                             log("Device doesn't support encryption; failing");
    264                             tagIsSupported = false;
    265                         }
    266                         // If we fall through, we can't support the policy
    267                         unsupportedList.add(R.string.policy_require_sd_encryption);
    268                     }
    269                     break;
    270                     // Note this policy; we enforce it in ExchangeService
    271                 case Tags.PROVISION_REQUIRE_MANUAL_SYNC_WHEN_ROAMING:
    272                     policy.mRequireManualSyncWhenRoaming = getValueInt() == 1;
    273                     break;
    274                 // We are allowed to accept policies, regardless of value of this tag
    275                 // TODO: When we DO support a recovery password, we need to store the value in
    276                 // the account (so we know to utilize it)
    277                 case Tags.PROVISION_PASSWORD_RECOVERY_ENABLED:
    278                     // Read, but ignore, value
    279                     policy.mPasswordRecoveryEnabled = getValueInt() == 1;
    280                     break;
    281                 // The following policies, if true, can't be supported at the moment
    282                 case Tags.PROVISION_REQUIRE_SIGNED_SMIME_MESSAGES:
    283                 case Tags.PROVISION_REQUIRE_ENCRYPTED_SMIME_MESSAGES:
    284                 case Tags.PROVISION_REQUIRE_SIGNED_SMIME_ALGORITHM:
    285                 case Tags.PROVISION_REQUIRE_ENCRYPTION_SMIME_ALGORITHM:
    286                     if (getValueInt() == 1) {
    287                         tagIsSupported = false;
    288                         if (!smimeRequired) {
    289                             unsupportedList.add(R.string.policy_require_smime);
    290                             smimeRequired = true;
    291                         }
    292                     }
    293                     break;
    294                 case Tags.PROVISION_MAX_ATTACHMENT_SIZE:
    295                     int max = getValueInt();
    296                     if (max > 0) {
    297                         policy.mMaxAttachmentSize = max;
    298                     }
    299                     break;
    300                 // Complex characters are supported
    301                 case Tags.PROVISION_MIN_DEVICE_PASSWORD_COMPLEX_CHARS:
    302                     policy.mPasswordComplexChars = getValueInt();
    303                     break;
    304                 // The following policies are moot; they allow functionality that we don't support
    305                 case Tags.PROVISION_ALLOW_DESKTOP_SYNC:
    306                 case Tags.PROVISION_ALLOW_SMIME_ENCRYPTION_NEGOTIATION:
    307                 case Tags.PROVISION_ALLOW_SMIME_SOFT_CERTS:
    308                 case Tags.PROVISION_ALLOW_REMOTE_DESKTOP:
    309                     skipTag();
    310                     break;
    311                 // We don't handle approved/unapproved application lists
    312                 case Tags.PROVISION_UNAPPROVED_IN_ROM_APPLICATION_LIST:
    313                 case Tags.PROVISION_APPROVED_APPLICATION_LIST:
    314                     // Parse and throw away the content
    315                     if (specifiesApplications(tag)) {
    316                         tagIsSupported = false;
    317                         if (tag == Tags.PROVISION_UNAPPROVED_IN_ROM_APPLICATION_LIST) {
    318                             unsupportedList.add(R.string.policy_app_blacklist);
    319                         } else {
    320                             unsupportedList.add(R.string.policy_app_whitelist);
    321                         }
    322                     }
    323                     break;
    324                 // We accept calendar age, since we never ask for more than two weeks, and that's
    325                 // the most restrictive policy
    326                 case Tags.PROVISION_MAX_CALENDAR_AGE_FILTER:
    327                     policy.mMaxCalendarLookback = getValueInt();
    328                     break;
    329                 // We handle max email lookback
    330                 case Tags.PROVISION_MAX_EMAIL_AGE_FILTER:
    331                     policy.mMaxEmailLookback = getValueInt();
    332                     break;
    333                 // We currently reject these next two policies
    334                 case Tags.PROVISION_MAX_EMAIL_BODY_TRUNCATION_SIZE:
    335                 case Tags.PROVISION_MAX_EMAIL_HTML_BODY_TRUNCATION_SIZE:
    336                     String value = getValue();
    337                     // -1 indicates no required truncation
    338                     if (!value.equals("-1")) {
    339                         max = Integer.parseInt(value);
    340                         if (tag == Tags.PROVISION_MAX_EMAIL_BODY_TRUNCATION_SIZE) {
    341                             policy.mMaxTextTruncationSize = max;
    342                             unsupportedList.add(R.string.policy_text_truncation);
    343                         } else {
    344                             policy.mMaxHtmlTruncationSize = max;
    345                             unsupportedList.add(R.string.policy_html_truncation);
    346                         }
    347                         tagIsSupported = false;
    348                     }
    349                     break;
    350                 default:
    351                     skipTag();
    352             }
    353 
    354             if (!tagIsSupported) {
    355                 log("Policy not supported: " + tag);
    356                 mIsSupportable = false;
    357             }
    358         }
    359 
    360         // Make sure policy settings are valid; password not enabled trumps other password settings
    361         if (!passwordEnabled) {
    362             policy.mPasswordMode = Policy.PASSWORD_MODE_NONE;
    363         }
    364 
    365         if (!unsupportedList.isEmpty()) {
    366             StringBuilder sb = new StringBuilder();
    367             for (int res: unsupportedList) {
    368                 addPolicyString(sb, res);
    369             }
    370             policy.mProtocolPoliciesUnsupported = sb.toString();
    371         }
    372 
    373         setPolicy(policy);
    374     }
    375 
    376     /**
    377      * Return whether or not either of the application list tags specifies any applications
    378      * @param endTag the tag whose children we're walking through
    379      * @return whether any applications were specified (by name or by hash)
    380      * @throws IOException
    381      */
    382     private boolean specifiesApplications(int endTag) throws IOException {
    383         boolean specifiesApplications = false;
    384         while (nextTag(endTag) != END) {
    385             switch (tag) {
    386                 case Tags.PROVISION_APPLICATION_NAME:
    387                 case Tags.PROVISION_HASH:
    388                     specifiesApplications = true;
    389                     break;
    390                 default:
    391                     skipTag();
    392             }
    393         }
    394         return specifiesApplications;
    395     }
    396 
    397     /*package*/ void parseProvisionDocXml(String doc) throws IOException {
    398         Policy policy = new Policy();
    399 
    400         try {
    401             XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    402             XmlPullParser parser = factory.newPullParser();
    403             parser.setInput(new ByteArrayInputStream(doc.getBytes()), "UTF-8");
    404             int type = parser.getEventType();
    405             if (type == XmlPullParser.START_DOCUMENT) {
    406                 type = parser.next();
    407                 if (type == XmlPullParser.START_TAG) {
    408                     String tagName = parser.getName();
    409                     if (tagName.equals("wap-provisioningdoc")) {
    410                         parseWapProvisioningDoc(parser, policy);
    411                     }
    412                 }
    413             }
    414         } catch (XmlPullParserException e) {
    415            throw new IOException();
    416         }
    417 
    418         setPolicy(policy);
    419     }
    420 
    421     /**
    422      * Return true if password is required; otherwise false.
    423      */
    424     private boolean parseSecurityPolicy(XmlPullParser parser, Policy policy)
    425             throws XmlPullParserException, IOException {
    426         boolean passwordRequired = true;
    427         while (true) {
    428             int type = parser.nextTag();
    429             if (type == XmlPullParser.END_TAG && parser.getName().equals("characteristic")) {
    430                 break;
    431             } else if (type == XmlPullParser.START_TAG) {
    432                 String tagName = parser.getName();
    433                 if (tagName.equals("parm")) {
    434                     String name = parser.getAttributeValue(null, "name");
    435                     if (name.equals("4131")) {
    436                         String value = parser.getAttributeValue(null, "value");
    437                         if (value.equals("1")) {
    438                             passwordRequired = false;
    439                         }
    440                     }
    441                 }
    442             }
    443         }
    444         return passwordRequired;
    445     }
    446 
    447     private void parseCharacteristic(XmlPullParser parser, Policy policy)
    448             throws XmlPullParserException, IOException {
    449         boolean enforceInactivityTimer = true;
    450         while (true) {
    451             int type = parser.nextTag();
    452             if (type == XmlPullParser.END_TAG && parser.getName().equals("characteristic")) {
    453                 break;
    454             } else if (type == XmlPullParser.START_TAG) {
    455                 if (parser.getName().equals("parm")) {
    456                     String name = parser.getAttributeValue(null, "name");
    457                     String value = parser.getAttributeValue(null, "value");
    458                     if (name.equals("AEFrequencyValue")) {
    459                         if (enforceInactivityTimer) {
    460                             if (value.equals("0")) {
    461                                 policy.mMaxScreenLockTime = 1;
    462                             } else {
    463                                 policy.mMaxScreenLockTime = 60*Integer.parseInt(value);
    464                             }
    465                         }
    466                     } else if (name.equals("AEFrequencyType")) {
    467                         // "0" here means we don't enforce an inactivity timeout
    468                         if (value.equals("0")) {
    469                             enforceInactivityTimer = false;
    470                         }
    471                     } else if (name.equals("DeviceWipeThreshold")) {
    472                         policy.mPasswordMaxFails = Integer.parseInt(value);
    473                     } else if (name.equals("CodewordFrequency")) {
    474                         // Ignore; has no meaning for us
    475                     } else if (name.equals("MinimumPasswordLength")) {
    476                         policy.mPasswordMinLength = Integer.parseInt(value);
    477                     } else if (name.equals("PasswordComplexity")) {
    478                         if (value.equals("0")) {
    479                             policy.mPasswordMode = Policy.PASSWORD_MODE_STRONG;
    480                         } else {
    481                             policy.mPasswordMode = Policy.PASSWORD_MODE_SIMPLE;
    482                         }
    483                     }
    484                 }
    485             }
    486         }
    487     }
    488 
    489     private void parseRegistry(XmlPullParser parser, Policy policy)
    490             throws XmlPullParserException, IOException {
    491       while (true) {
    492           int type = parser.nextTag();
    493           if (type == XmlPullParser.END_TAG && parser.getName().equals("characteristic")) {
    494               break;
    495           } else if (type == XmlPullParser.START_TAG) {
    496               String name = parser.getName();
    497               if (name.equals("characteristic")) {
    498                   parseCharacteristic(parser, policy);
    499               }
    500           }
    501       }
    502     }
    503 
    504     private void parseWapProvisioningDoc(XmlPullParser parser, Policy policy)
    505             throws XmlPullParserException, IOException {
    506         while (true) {
    507             int type = parser.nextTag();
    508             if (type == XmlPullParser.END_TAG && parser.getName().equals("wap-provisioningdoc")) {
    509                 break;
    510             } else if (type == XmlPullParser.START_TAG) {
    511                 String name = parser.getName();
    512                 if (name.equals("characteristic")) {
    513                     String atype = parser.getAttributeValue(null, "type");
    514                     if (atype.equals("SecurityPolicy")) {
    515                         // If a password isn't required, stop here
    516                         if (!parseSecurityPolicy(parser, policy)) {
    517                             return;
    518                         }
    519                     } else if (atype.equals("Registry")) {
    520                         parseRegistry(parser, policy);
    521                         return;
    522                     }
    523                 }
    524             }
    525         }
    526     }
    527 
    528     private void parseProvisionData() throws IOException {
    529         while (nextTag(Tags.PROVISION_DATA) != END) {
    530             if (tag == Tags.PROVISION_EAS_PROVISION_DOC) {
    531                 parseProvisionDocWbxml();
    532             } else {
    533                 skipTag();
    534             }
    535         }
    536     }
    537 
    538     private void parsePolicy() throws IOException {
    539         String policyType = null;
    540         while (nextTag(Tags.PROVISION_POLICY) != END) {
    541             switch (tag) {
    542                 case Tags.PROVISION_POLICY_TYPE:
    543                     policyType = getValue();
    544                     mService.userLog("Policy type: ", policyType);
    545                     break;
    546                 case Tags.PROVISION_POLICY_KEY:
    547                     mSecuritySyncKey = getValue();
    548                     break;
    549                 case Tags.PROVISION_STATUS:
    550                     mService.userLog("Policy status: ", getValue());
    551                     break;
    552                 case Tags.PROVISION_DATA:
    553                     if (policyType.equalsIgnoreCase(EasSyncService.EAS_2_POLICY_TYPE)) {
    554                         // Parse the old style XML document
    555                         parseProvisionDocXml(getValue());
    556                     } else {
    557                         // Parse the newer WBXML data
    558                         parseProvisionData();
    559                     }
    560                     break;
    561                 default:
    562                     skipTag();
    563             }
    564         }
    565     }
    566 
    567     private void parsePolicies() throws IOException {
    568         while (nextTag(Tags.PROVISION_POLICIES) != END) {
    569             if (tag == Tags.PROVISION_POLICY) {
    570                 parsePolicy();
    571             } else {
    572                 skipTag();
    573             }
    574         }
    575     }
    576 
    577     private void parseDeviceInformation() throws IOException {
    578         while (nextTag(Tags.SETTINGS_DEVICE_INFORMATION) != END) {
    579             if (tag == Tags.SETTINGS_STATUS) {
    580                 mService.userLog("DeviceInformation status: " + getValue());
    581             } else {
    582                 skipTag();
    583             }
    584         }
    585     }
    586 
    587     @Override
    588     public boolean parse() throws IOException {
    589         boolean res = false;
    590         if (nextTag(START_DOCUMENT) != Tags.PROVISION_PROVISION) {
    591             throw new IOException();
    592         }
    593         while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
    594             switch (tag) {
    595                 case Tags.PROVISION_STATUS:
    596                     int status = getValueInt();
    597                     mService.userLog("Provision status: ", status);
    598                     res = (status == 1);
    599                     break;
    600                 case Tags.SETTINGS_DEVICE_INFORMATION:
    601                     parseDeviceInformation();
    602                     break;
    603                 case Tags.PROVISION_POLICIES:
    604                     parsePolicies();
    605                     break;
    606                 case Tags.PROVISION_REMOTE_WIPE:
    607                     // Indicate remote wipe command received
    608                     mRemoteWipe = true;
    609                     break;
    610                 default:
    611                     skipTag();
    612             }
    613         }
    614         return res;
    615     }
    616 }
    617