summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryingying <yingying@codeaurora.org>2014-04-02 19:33:28 +0800
committerLorDClockaN <davor@losinj.com>2014-08-27 22:26:17 +0200
commit505a0cfc994e642287494da30f0d124209e6f154 (patch)
tree66b62a04227ec7dae6ad19d18dcc588296fd27b2
parentb428212be452f58c1dba9556805c0b1dbbd241cf (diff)
Exchange: Add the dummy attachment as load more place holder.
- Add the place holder attachment for the uncomplete mail. - Update the body's html content for viewable attachments. CRs-fixed: 642921 Change-Id: Iba64b5ac7cfd4f02d948bc3cb4eb400d568a4165
-rw-r--r--src/com/android/exchange/adapter/EmailSyncAdapter.java99
-rw-r--r--src/com/android/exchange/adapter/EmailSyncParser.java95
-rw-r--r--src/com/android/exchange/adapter/LoadMore.java10
3 files changed, 182 insertions, 22 deletions
diff --git a/src/com/android/exchange/adapter/EmailSyncAdapter.java b/src/com/android/exchange/adapter/EmailSyncAdapter.java
index 0527c3d9..db66edfa 100644
--- a/src/com/android/exchange/adapter/EmailSyncAdapter.java
+++ b/src/com/android/exchange/adapter/EmailSyncAdapter.java
@@ -20,6 +20,7 @@
package com.android.exchange.adapter;
import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -48,6 +49,7 @@ import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.EmailContent.Attachment;
import com.android.emailcommon.provider.EmailContent.Body;
+import com.android.emailcommon.provider.EmailContent.BodyColumns;
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.EmailContent.MessageColumns;
@@ -558,7 +560,7 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
msg.mFlagRead = getValueInt() == 1;
break;
case Tags.BASE_BODY:
- bodyParser(msg);
+ bodyParser(atts, msg);
break;
case Tags.EMAIL_FLAG:
msg.mFlagFavorite = flagParser();
@@ -780,9 +782,13 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
return state;
}
- private void bodyParser(Message msg) throws IOException {
+ private void bodyParser(ArrayList<EmailContent.Attachment> atts,
+ Message msg) throws IOException {
String bodyType = Eas.BODY_PREFERENCE_TEXT;
String body = "";
+ String length = null;
+ boolean truncated = false;
+
while (nextTag(Tags.EMAIL_BODY) != END) {
switch (tag) {
case Tags.BASE_TYPE:
@@ -792,10 +798,10 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
body = getValue();
break;
case Tags.BASE_TRUNCATED:
- boolean truncated = getValue().equals("1") ? true : false;
- if (truncated) {
- msg.mFlagLoaded = Message.FLAG_LOADED_PARTIAL_COMPLETE;
- }
+ truncated = getValueInt() == 1;
+ break;
+ case Tags.BASE_ESTIMATED_DATA_SIZE:
+ length = getValue();
break;
default:
skipTag();
@@ -807,6 +813,20 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
} else {
msg.mText = body;
}
+
+ // If the content is truncated, we will insert one dummy attachment
+ // as the placeholder which is same as POP3 and IMAP. More details
+ // please refer to the Utilities in the Email.
+ if (truncated) {
+ msg.mFlagLoaded = Message.FLAG_LOADED_PARTIAL_COMPLETE;
+ EmailContent.Attachment att = new EmailContent.Attachment();
+ att.mFileName = "";
+ att.mSize = Long.parseLong(length);
+ att.mMimeType = "text/plain";
+ att.mAccountKey = mAccount.mId;
+ att.mFlags = Attachment.FLAG_DUMMY_ATTACHMENT;
+ atts.add(att);
+ }
}
/**
@@ -898,6 +918,9 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
// contentId rather than contentLocation, when sent from Ex03, Ex07, and Ex10
if (isInline && !TextUtils.isEmpty(contentId)) {
att.mContentId = contentId;
+ } else {
+ // This isn't the viewable part, set the local message has attachment.
+ msg.mFlagAttachment = true;
}
// Check if this attachment can't be downloaded due to an account policy
if (mPolicy != null) {
@@ -908,7 +931,6 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
}
}
atts.add(att);
- msg.mFlagAttachment = true;
}
}
@@ -1187,11 +1209,18 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
.withSelection(EmailContent.RECORD_ID + "=?", bindArgument)
.withValue(Message.FLAG_LOADED, Message.FLAG_LOADED_COMPLETE)
.build());
+ // apply these ops first.
+ applyBatch(ops, tryCount);
}
}
for (Message msg: newEmails) {
msg.addSaveOps(ops);
+ // apply these ops and get the result.
+ ContentProviderResult[] res = applyBatch(ops, tryCount);
+ // After the message and attachments saved, we need update the message body's
+ // HTML content for the viewable parts.
+ updateBodyForInlineAttachment(ops, res, msg, tryCount);
}
for (Long id : deletedEmails) {
@@ -1240,6 +1269,62 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
}
}
+ private ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> ops,
+ int tryCount) {
+ ContentProviderResult[] res = null;
+ try {
+ res = mContentResolver.applyBatch(EmailContent.AUTHORITY, ops);
+ ops.clear();
+ } catch (TransactionTooLargeException e) {
+ LogUtils.w(TAG, "Transaction failed on fetched message; retrying...");
+ commitImpl(++tryCount);
+ } catch (RemoteException e) {
+ // There is nothing to be done here; fail by returning null
+ } catch (OperationApplicationException e) {
+ // There is nothing to be done here; fail by returning null
+ }
+
+ return res;
+ }
+
+ private void updateBodyForInlineAttachment(ArrayList<ContentProviderOperation> ops,
+ ContentProviderResult[] res, EmailContent.Message msg, int tryCount) {
+ if (msg == null || msg.mHtml == null || res == null) {
+ // There isn't HTML content, do nothing.
+ return;
+ }
+
+ // Find the message's id.
+ long msgId = -1;
+ try {
+ for (ContentProviderResult result : res) {
+ if (result.uri.getPath().startsWith(
+ EmailContent.Message.CONTENT_URI.getPath())) {
+ msgId = Long.parseLong(result.uri.getLastPathSegment());
+ break;
+ }
+ }
+ } catch (NumberFormatException e) {
+ // Meet the format exception.
+ return;
+ } finally {
+ if (msgId < 0) return;
+ }
+
+ // Get the attachments to update the HTML content.
+ String newContent = Message.updateHTMLContentForInlineAtts(mContext, msg.mHtml, msgId);
+ if (newContent != null) {
+ long bodyId = Body.lookupBodyIdWithMessageId(mContext, msgId);
+ ContentValues cv = new ContentValues();
+ cv.put(BodyColumns.HTML_CONTENT, newContent);
+ ops.add(ContentProviderOperation.newUpdate(
+ ContentUris.withAppendedId(EmailContent.Body.CONTENT_URI, bodyId))
+ .withValues(cv)
+ .build());
+ applyBatch(ops, tryCount);
+ }
+ }
+
@Override
protected void wipe() {
// This file is deprecated, no need to implement this.
diff --git a/src/com/android/exchange/adapter/EmailSyncParser.java b/src/com/android/exchange/adapter/EmailSyncParser.java
index b3f9ac1f..c2febfd3 100644
--- a/src/com/android/exchange/adapter/EmailSyncParser.java
+++ b/src/com/android/exchange/adapter/EmailSyncParser.java
@@ -1,6 +1,7 @@
package com.android.exchange.adapter;
import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -30,6 +31,9 @@ import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.provider.Policy;
import com.android.emailcommon.provider.ProviderUnavailableException;
+import com.android.emailcommon.provider.EmailContent.Attachment;
+import com.android.emailcommon.provider.EmailContent.Body;
+import com.android.emailcommon.provider.EmailContent.BodyColumns;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.utility.AttachmentUtilities;
import com.android.emailcommon.utility.ConversionUtilities;
@@ -164,7 +168,7 @@ public class EmailSyncParser extends AbstractSyncParser {
msg.mFlagRead = getValueInt() == 1;
break;
case Tags.BASE_BODY:
- bodyParser(msg);
+ bodyParser(atts, msg);
break;
case Tags.EMAIL_FLAG:
msg.mFlagFavorite = flagParser();
@@ -386,9 +390,13 @@ public class EmailSyncParser extends AbstractSyncParser {
return state;
}
- private void bodyParser(EmailContent.Message msg) throws IOException {
+ private void bodyParser(ArrayList<EmailContent.Attachment> atts,
+ EmailContent.Message msg) throws IOException {
String bodyType = Eas.BODY_PREFERENCE_TEXT;
String body = "";
+ String length = null;
+ boolean truncated = false;
+
while (nextTag(Tags.EMAIL_BODY) != END) {
switch (tag) {
case Tags.BASE_TYPE:
@@ -398,10 +406,10 @@ public class EmailSyncParser extends AbstractSyncParser {
body = getValue();
break;
case Tags.BASE_TRUNCATED:
- boolean truncated = getValue().equals("1") ? true : false;
- if (truncated) {
- msg.mFlagLoaded = Message.FLAG_LOADED_PARTIAL_COMPLETE;
- }
+ truncated = getValueInt() == 1;
+ break;
+ case Tags.BASE_ESTIMATED_DATA_SIZE:
+ length = getValue();
break;
default:
skipTag();
@@ -413,6 +421,20 @@ public class EmailSyncParser extends AbstractSyncParser {
} else {
msg.mText = body;
}
+
+ // If the content is truncated, we will insert one dummy attachment
+ // as the placeholder which is same as POP3 and IMAP. More details
+ // please refer to the Utilities in the Email.
+ if (truncated) {
+ msg.mFlagLoaded = Message.FLAG_LOADED_PARTIAL_COMPLETE;
+ EmailContent.Attachment att = new EmailContent.Attachment();
+ att.mFileName = "";
+ att.mSize = Long.parseLong(length);
+ att.mMimeType = "text/plain";
+ att.mAccountKey = mAccount.mId;
+ att.mFlags = Attachment.FLAG_DUMMY_ATTACHMENT;
+ atts.add(att);
+ }
}
/**
@@ -507,6 +529,9 @@ public class EmailSyncParser extends AbstractSyncParser {
// contentId rather than contentLocation, when sent from Ex03, Ex07, and Ex10
if (isInline && !TextUtils.isEmpty(contentId)) {
att.mContentId = contentId;
+ } else {
+ // This isn't the viewable part, set the local message has attachment.
+ msg.mFlagAttachment = true;
}
// Check if this attachment can't be downloaded due to an account policy
if (mPolicy != null) {
@@ -517,7 +542,6 @@ public class EmailSyncParser extends AbstractSyncParser {
}
}
atts.add(att);
- msg.mFlagAttachment = true;
}
}
@@ -839,12 +863,17 @@ public class EmailSyncParser extends AbstractSyncParser {
EmailContent.Message.FLAG_LOADED_COMPLETE)
.build());
}
- applyBatchIfNeeded(ops, maxOpsPerBatch, false);
+ // As we need get the new msg's id, so we will force to apply batch for these ops.
+ applyBatchIfNeeded(ops, maxOpsPerBatch, true);
}
for (EmailContent.Message msg: newEmails) {
msg.addSaveOps(ops);
- applyBatchIfNeeded(ops, maxOpsPerBatch, false);
+ // As we need get the new msg's id, so we will force to apply batch for these ops.
+ ContentProviderResult[] res = applyBatchIfNeeded(ops, maxOpsPerBatch, true);
+ // After the message and attachments saved, we need update the message body's
+ // HTML content for the viewable parts.
+ updateBodyForInlineAttachment(ops, res, msg);
}
for (Long id : deletedEmails) {
@@ -888,10 +917,11 @@ public class EmailSyncParser extends AbstractSyncParser {
// Check if there at least MAX_OPS_PER_BATCH ops in queue and flush if there are.
// If force is true, flush regardless of size.
- private void applyBatchIfNeeded(ArrayList<ContentProviderOperation> ops, int maxOpsPerBatch,
- boolean force)
+ private ContentProviderResult[] applyBatchIfNeeded(ArrayList<ContentProviderOperation> ops,
+ int maxOpsPerBatch, boolean force)
throws RemoteException, OperationApplicationException {
- if (force || ops.size() >= maxOpsPerBatch) {
+ ContentProviderResult[] res = null;
+ if (force || ops.size() >= maxOpsPerBatch) {
// STOPSHIP Remove calculating size of data before ship
if (LogUtils.isLoggable(TAG, Log.DEBUG)) {
final Parcel parcel = Parcel.obtain();
@@ -902,8 +932,47 @@ public class EmailSyncParser extends AbstractSyncParser {
ops.size(), parcel.dataSize()));
parcel.recycle();
}
- mContentResolver.applyBatch(EmailContent.AUTHORITY, ops);
+ res = mContentResolver.applyBatch(EmailContent.AUTHORITY, ops);
ops.clear();
}
+ return res;
+ }
+
+ private void updateBodyForInlineAttachment(ArrayList<ContentProviderOperation> ops,
+ ContentProviderResult[] res, EmailContent.Message msg)
+ throws RemoteException, OperationApplicationException {
+ if (msg == null || msg.mHtml == null || res == null) {
+ // There isn't HTML content, do nothing.
+ return;
+ }
+
+ // Find the message's id.
+ long msgId = -1;
+ try {
+ for (ContentProviderResult result : res) {
+ if (result.uri.getPath().startsWith(EmailContent.Message.CONTENT_URI.getPath())) {
+ msgId = Long.parseLong(result.uri.getLastPathSegment());
+ break;
+ }
+ }
+ } catch (NumberFormatException e) {
+ // Meet the format exception.
+ return;
+ } finally {
+ if (msgId < 0) return;
+ }
+
+ // Get the attachments to update the HTML content.
+ String newContent = Message.updateHTMLContentForInlineAtts(mContext, msg.mHtml, msgId);
+ if (newContent != null) {
+ long bodyId = Body.lookupBodyIdWithMessageId(mContext, msgId);
+ ContentValues cv = new ContentValues();
+ cv.put(BodyColumns.HTML_CONTENT, newContent);
+ ops.add(ContentProviderOperation.newUpdate(
+ ContentUris.withAppendedId(EmailContent.Body.CONTENT_URI, bodyId))
+ .withValues(cv)
+ .build());
+ applyBatchIfNeeded(ops, 0, true /* force */);
+ }
}
} \ No newline at end of file
diff --git a/src/com/android/exchange/adapter/LoadMore.java b/src/com/android/exchange/adapter/LoadMore.java
index f697ee0b..1c508566 100644
--- a/src/com/android/exchange/adapter/LoadMore.java
+++ b/src/com/android/exchange/adapter/LoadMore.java
@@ -142,7 +142,7 @@ public class LoadMore {
LoadMoreParser parser = new LoadMoreParser(is, msg);
parser.parse();
if (parser.getStatusCode() == LoadMoreParser.STATUS_CODE_SUCCESS) {
- parser.commit(cr);
+ parser.commit(context);
}
}
} else {
@@ -196,16 +196,22 @@ public class LoadMore {
}
// commit the body data to database.
- public void commit(ContentResolver contentResolver) {
+ public void commit(Context context) {
LogUtils.d(Logging.LOG_TAG, "Fetched message body successfully for " + mMessage.mId);
// update the body data
+ String newContent = Message.updateHTMLContentForInlineAtts(context,
+ mMessage.mHtml, mMessage.mId);
+ if (newContent != null) {
+ mMessage.mHtml = newContent;
+ }
ContentValues cv = new ContentValues();
if (mBodyType.equals(Eas.BODY_PREFERENCE_HTML)) {
cv.put(BodyColumns.HTML_CONTENT, mMessage.mHtml);
} else {
cv.put(BodyColumns.TEXT_CONTENT, mMessage.mText);
}
+ ContentResolver contentResolver = context.getContentResolver();
int res = contentResolver.update(Body.CONTENT_URI, cv,
BodyColumns.MESSAGE_KEY + "=" + mMessage.mId, null);
LogUtils.d(Logging.LOG_TAG, "update the body content, success number : " + res);