1 package com.android.exchange.adapter; 2 3 import android.content.ContentProviderOperation; 4 import android.content.ContentResolver; 5 import android.content.Context; 6 import android.content.OperationApplicationException; 7 import android.os.RemoteException; 8 9 import com.android.emailcommon.Logging; 10 import com.android.emailcommon.provider.Account; 11 import com.android.emailcommon.provider.EmailContent; 12 import com.android.emailcommon.provider.Mailbox; 13 import com.android.emailcommon.provider.EmailContent.Message; 14 import com.android.emailcommon.utility.TextUtilities; 15 import com.android.exchange.Eas; 16 import com.android.mail.utils.LogUtils; 17 18 import java.io.IOException; 19 import java.io.InputStream; 20 import java.util.ArrayList; 21 22 /** 23 * Parse the result of a Search command 24 */ 25 public class SearchParser extends Parser { 26 private static final String LOG_TAG = Logging.LOG_TAG; 27 private final Context mContext; 28 private final ContentResolver mContentResolver; 29 private final Mailbox mMailbox; 30 private final Account mAccount; 31 private final String mQuery; 32 private int mTotalResults; 33 34 public SearchParser(final Context context, final ContentResolver resolver, 35 final InputStream in, final Mailbox mailbox, final Account account, 36 String query) 37 throws IOException { 38 super(in); 39 mContext = context; 40 mContentResolver = resolver; 41 mMailbox = mailbox; 42 mAccount = account; 43 mQuery = query; 44 } 45 46 public int getTotalResults() { 47 return mTotalResults; 48 } 49 50 @Override 51 public boolean parse() throws IOException { 52 boolean res = false; 53 if (nextTag(START_DOCUMENT) != Tags.SEARCH_SEARCH) { 54 throw new IOException(); 55 } 56 while (nextTag(START_DOCUMENT) != END_DOCUMENT) { 57 if (tag == Tags.SEARCH_STATUS) { 58 String status = getValue(); 59 if (Eas.USER_LOG) { 60 LogUtils.d(Logging.LOG_TAG, "Search status: " + status); 61 } 62 } else if (tag == Tags.SEARCH_RESPONSE) { 63 parseResponse(); 64 } else { 65 skipTag(); 66 } 67 } 68 return res; 69 } 70 71 private boolean parseResponse() throws IOException { 72 boolean res = false; 73 while (nextTag(Tags.SEARCH_RESPONSE) != END) { 74 if (tag == Tags.SEARCH_STORE) { 75 parseStore(); 76 } else { 77 skipTag(); 78 } 79 } 80 return res; 81 } 82 83 private boolean parseStore() throws IOException { 84 EmailSyncParser parser = new EmailSyncParser(this, mContext, mContentResolver, 85 mMailbox, mAccount); 86 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); 87 boolean res = false; 88 89 while (nextTag(Tags.SEARCH_STORE) != END) { 90 if (tag == Tags.SEARCH_STATUS) { 91 getValue(); 92 } else if (tag == Tags.SEARCH_TOTAL) { 93 mTotalResults = getValueInt(); 94 } else if (tag == Tags.SEARCH_RESULT) { 95 parseResult(parser, ops); 96 } else { 97 skipTag(); 98 } 99 } 100 101 try { 102 // FLAG: In EmailSyncParser.commit(), we have complicated logic to constrain the size 103 // of the batch, and fall back to one op at a time if that fails. We don't have any 104 // such logic here, but we probably should. 105 mContentResolver.applyBatch(EmailContent.AUTHORITY, ops); 106 LogUtils.d(Logging.LOG_TAG, "Saved %s search results", ops.size()); 107 } catch (RemoteException e) { 108 LogUtils.d(Logging.LOG_TAG, "RemoteException while saving search results."); 109 } catch (OperationApplicationException e) { 110 } 111 112 return res; 113 } 114 115 private boolean parseResult(EmailSyncParser parser, 116 ArrayList<ContentProviderOperation> ops) throws IOException { 117 boolean res = false; 118 Message msg = new Message(); 119 while (nextTag(Tags.SEARCH_RESULT) != END) { 120 if (tag == Tags.SYNC_CLASS) { 121 getValue(); 122 } else if (tag == Tags.SYNC_COLLECTION_ID) { 123 getValue(); 124 } else if (tag == Tags.SEARCH_LONG_ID) { 125 msg.mProtocolSearchInfo = getValue(); 126 } else if (tag == Tags.SEARCH_PROPERTIES) { 127 msg.mAccountKey = mAccount.mId; 128 msg.mMailboxKey = mMailbox.mId; 129 msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; 130 // Delegate parsing of the properties to the EmailSyncParser. 131 132 // We push a new <Properties> tag onto the EmailSyncParser. It will parse 133 // until it consumes the </Properties> 134 parser.pushTag(tag); 135 // Since the EmailSyncParser is responsible for consuming the </Properties> 136 // tag, we need to remove it from our stack or it will be double counted. 137 pop(); 138 139 parser.addData(msg, tag); 140 if (msg.mHtml != null) { 141 msg.mHtml = TextUtilities.highlightTermsInHtml(msg.mHtml, mQuery); 142 } 143 msg.addSaveOps(ops); 144 } else { 145 skipTag(); 146 } 147 } 148 return res; 149 } 150 } 151