Merge "b/14075613. Don't use indices created from html on text/plain strings." into ub-mail-master
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index 7903ab9..78cebdb 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -951,7 +951,7 @@
int mode = getMode();
state.putInt(EXTRA_ACTION, mode);
- final Message message = createMessage(selectedReplyFromAccount, mode);
+ final Message message = createMessage(selectedReplyFromAccount, mRefMessage, mode);
if (mDraft != null) {
message.id = mDraft.id;
message.serverId = mDraft.serverId;
@@ -986,7 +986,8 @@
return mode;
}
- private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
+ private Message createMessage(ReplyFromAccount selectedReplyFromAccount, Message refMessage,
+ int mode) {
Message message = new Message();
message.id = UIProvider.INVALID_MESSAGE_ID;
message.serverId = null;
@@ -1011,8 +1012,18 @@
message.alwaysShowImages = false;
message.attachmentsJson = Attachment.toJSONArray(attachments);
CharSequence quotedText = mQuotedTextView.getQuotedText();
- message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
- .getQuotedTextOffset(quotedText.toString()) : -1;
+ message.quotedTextOffset = -1; // Just a default value.
+ if (refMessage != null && !TextUtils.isEmpty(quotedText)) {
+ if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
+ // We want the index to point to just the quoted text and not the
+ // "On December 25, 2014..." part of it.
+ message.quotedTextOffset =
+ QuotedTextView.getQuotedTextOffset(quotedText.toString());
+ } else if (!TextUtils.isEmpty(refMessage.bodyText)) {
+ // We want to point to the entire quoted text.
+ message.quotedTextOffset = QuotedTextView.findQuotedTextIndex(quotedText);
+ }
+ }
message.accountUri = null;
final String email = selectedReplyFromAccount != null ? selectedReplyFromAccount.address
: mAccount != null ? mAccount.getEmailAddress() : null;
@@ -1371,14 +1382,17 @@
addAttachmentAndUpdateView(a);
}
}
- int quotedTextIndex = message.appendRefMessageContent ?
- message.quotedTextOffset : -1;
+ int quotedTextIndex = message.appendRefMessageContent ? message.quotedTextOffset : -1;
// Set the body
CharSequence quotedText = null;
if (!TextUtils.isEmpty(message.bodyHtml)) {
CharSequence htmlText = "";
if (quotedTextIndex > -1) {
- // Find the offset in the htmltext of the actual quoted text and strip it out.
+ // Find the offset in the html text of the actual quoted text and strip it out.
+ // Note that the actual quotedTextOffset in the message has not changed as
+ // this different offset is used only for display purposes. They point to different
+ // parts of the original message. Please see the comments in QuoteTextView
+ // to see the differences.
quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
if (quotedTextIndex > -1) {
htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
@@ -1392,13 +1406,23 @@
mBodyView.setText(htmlText);
} else {
final String body = message.bodyText;
- final CharSequence bodyText = !TextUtils.isEmpty(body) ?
- (quotedTextIndex > -1 ?
- message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
- : "";
- if (quotedTextIndex > -1) {
- quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
- : null;
+ final CharSequence bodyText;
+ if (TextUtils.isEmpty(body)) {
+ bodyText = "";
+ quotedText = null;
+ } else {
+ if (quotedTextIndex > body.length()) {
+ // Sanity check to guarantee that we will not over index the String.
+ // If this happens there is a bigger problem. This should never happen hence
+ // the wtf logging.
+ quotedTextIndex = -1;
+ LogUtils.wtf(LOG_TAG, "quotedTextIndex (%d) > body.length() (%d)",
+ quotedTextIndex, body.length());
+ }
+ bodyText = quotedTextIndex > -1 ? body.substring(0, quotedTextIndex) : body;
+ if (quotedTextIndex > -1) {
+ quotedText = body.substring(quotedTextIndex);
+ }
}
mBodyView.setText(bodyText);
}
@@ -2841,46 +2865,63 @@
MessageModification.putToAddresses(values, message.getToAddresses());
MessageModification.putCcAddresses(values, message.getCcAddresses());
MessageModification.putBccAddresses(values, message.getBccAddresses());
-
MessageModification.putCustomFromAddress(values, message.getFrom());
MessageModification.putSubject(values, message.subject);
+
// Make sure to remove only the composing spans from the Spannable before saving.
final String htmlBody = Html.toHtml(removeComposingSpans(body));
-
- boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
- StringBuilder fullBody = new StringBuilder(htmlBody);
- if (includeQuotedText) {
- // HTML gets converted to text for now
- final String text = quotedText.toString();
- if (QuotedTextView.containsQuotedText(text)) {
- int pos = QuotedTextView.getQuotedTextOffset(text);
- final int quoteStartPos = fullBody.length() + pos;
- fullBody.append(text);
- MessageModification.putQuoteStartPos(values, quoteStartPos);
- MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
- MessageModification.putAppendRefMessageContent(values, true /* include quoted */);
- } else {
- LogUtils.w(LOG_TAG, "Couldn't find quoted text");
- // This shouldn't happen, but just use what we have,
- // and don't do server-side expansion
- fullBody.append(text);
- }
+ final String textBody = Utils.convertHtmlToPlainText(htmlBody);
+ // fullbody will contain the actual body plus the quoted text.
+ final String fullBody;
+ final String quotedString;
+ final boolean hasQuotedText = !TextUtils.isEmpty(quotedText);
+ if (hasQuotedText) {
+ // The quoted text is HTML at this point.
+ quotedString = quotedText.toString();
+ fullBody = htmlBody + quotedString;
+ MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
+ MessageModification.putAppendRefMessageContent(values, true /* include quoted */);
+ } else {
+ fullBody = htmlBody;
+ quotedString = null;
}
- int draftType = getDraftType(composeMode);
- MessageModification.putDraftType(values, draftType);
if (refMessage != null) {
+ // The code below might need to be revisited. The quoted text position is different
+ // between text/html and text/plain parts and they should be stored seperately and
+ // the right version should be used in the UI. text/html should have preference
+ // if both exist. Issues like this made me file b/14256940 to make sure that we
+ // properly handle the existing of both text/html and text/plain parts and to verify
+ // that we are not making some assumptions that break if there is no text/html part.
+ int quotedTextPos = -1;
if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
MessageModification.putBodyHtml(values, fullBody.toString());
+ if (hasQuotedText) {
+ quotedTextPos = htmlBody.length() +
+ QuotedTextView.getQuotedTextOffset(quotedString);
+ }
}
if (!TextUtils.isEmpty(refMessage.bodyText)) {
MessageModification.putBody(values,
Utils.convertHtmlToPlainText(fullBody.toString()));
+ if (hasQuotedText && (quotedTextPos == -1)) {
+ quotedTextPos = textBody.length();
+ }
+ }
+ if (quotedTextPos != -1) {
+ // The quoted text pos is the text/html version first and the text/plan version
+ // if there is no text/html part. The reason for this is because preference
+ // is given to text/html in the compose window if it exists. In the future, we
+ // should calculate the index for both since the user could choose to compose
+ // explicitly in text/plain.
+ MessageModification.putQuoteStartPos(values, quotedTextPos);
}
} else {
MessageModification.putBodyHtml(values, fullBody.toString());
MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString()));
}
+ int draftType = getDraftType(composeMode);
+ MessageModification.putDraftType(values, draftType);
MessageModification.putAttachments(values, message.getAttachments());
if (!TextUtils.isEmpty(refMessageId)) {
MessageModification.putRefMessageId(values, refMessageId);
@@ -3028,7 +3069,7 @@
mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
}
- Message msg = createMessage(mReplyFromAccount, getMode());
+ Message msg = createMessage(mReplyFromAccount, mRefMessage, getMode());
mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
mQuotedTextView.getQuotedTextIfIncluded(), callback,
mSendSaveTaskHandler, save, mComposeMode, mDraftAccount, mExtraValues);
diff --git a/src/com/android/mail/compose/QuotedTextView.java b/src/com/android/mail/compose/QuotedTextView.java
index 2dd64d5..db35ae6 100644
--- a/src/com/android/mail/compose/QuotedTextView.java
+++ b/src/com/android/mail/compose/QuotedTextView.java
@@ -340,6 +340,13 @@
return pos >= 0;
}
+ /**
+ * Returns the index of the actual quoted text and NOT the meta information such as:
+ * "On April 4, 2013 Joe Smith <jsmith@example.com> wrote:" that is part of the original
+ * message when replying and including the original text.
+ * @param text HTML text that includes quoted text.
+ * @return The offset found.
+ */
public static int getQuotedTextOffset(String text) {
return text.indexOf(QuotedTextView.HEADER_SEPARATOR)
+ QuotedTextView.HEADER_SEPARATOR_LENGTH;