Merge "Support compose with quoted html." into jb-ub-mail-ur10
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 265b7b9..3c470ad 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -76,6 +76,8 @@
     <string name="reply_attribution">On <xliff:g id="date">%s</xliff:g>, <xliff:g id="person">%s</xliff:g> wrote:</string>
     <!-- Compose screen, displayed at the top of a message being forwarded. Please preserve the HTML entities (surrounded by & and ;). [CHAR LIMIT=1000] -->
     <string name="forward_attribution">---------- Forwarded message ----------&lt;br&gt;From: <xliff:g id="from">%1$s</xliff:g>&lt;br&gt;Date: <xliff:g id="date">%2$s</xliff:g>&lt;br&gt;Subject: <xliff:g id="subject">%3$s</xliff:g>&lt;br&gt;To: <xliff:g id="to">%4$s</xliff:g>&lt;br&gt;</string>
+    <!-- Compose screen, displayed at the top of a message being forwarded. [CHAR LIMIT=100]-->
+    <string name="forward_attribution_no_headers">---------- Forwarded message ----------</string>
     <!-- Compose screen, displayed at the top of a message being forwarded if there are any email addresses in the CC list. Please preserve the HTML entities (surrounded by & and ;). [CHAR LIMIT=1000]-->
     <string name="cc_attribution">Cc: <xliff:g id="cc">%1$s</xliff:g>&lt;br&gt;</string>
     <!-- Dialog text: select the type of an attachment while composing [CHAR LIMIT=100]-->
diff --git a/src/com/android/mail/compose/ComposeActivity.java b/src/com/android/mail/compose/ComposeActivity.java
index 3f7da5b..c80799d 100644
--- a/src/com/android/mail/compose/ComposeActivity.java
+++ b/src/com/android/mail/compose/ComposeActivity.java
@@ -34,6 +34,7 @@
 import android.content.Intent;
 import android.content.Loader;
 import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -123,11 +124,11 @@
         LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
         FeedbackEnabledActivity {
     // Identifiers for which type of composition this is
-    protected static final int COMPOSE = -1;
-    protected static final int REPLY = 0;
-    protected static final int REPLY_ALL = 1;
-    protected static final int FORWARD = 2;
-    protected static final int EDIT_DRAFT = 3;
+    public static final int COMPOSE = -1;
+    public static final int REPLY = 0;
+    public static final int REPLY_ALL = 1;
+    public static final int FORWARD = 2;
+    public static final int EDIT_DRAFT = 3;
 
     // Integer extra holding one of the above compose action
     protected static final String EXTRA_ACTION = "action";
@@ -145,6 +146,11 @@
 
     private static final String EXTRA_BODY = "body";
 
+    /**
+     * Expected to be html formatted text.
+     */
+    private static final String EXTRA_QUOTED_TEXT = "quotedText";
+
     protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
 
     private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
@@ -155,7 +161,8 @@
     private static final String EXTRA_BCC = "bcc";
 
     // List of all the fields
-    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
+    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC,
+            EXTRA_QUOTED_TEXT };
 
     private static SendOrSaveCallback sTestSendOrSaveCallback = null;
     // Map containing information about requests to create new messages, and the id of the
@@ -284,21 +291,29 @@
      * Can be called from a non-UI thread.
      */
     public static void editDraft(Context launcher, Account account, Message message) {
-        launch(launcher, account, message, EDIT_DRAFT, null, null);
+        launch(launcher, account, message, EDIT_DRAFT, null, null, null, null);
     }
 
     /**
      * Can be called from a non-UI thread.
      */
     public static void compose(Context launcher, Account account) {
-        launch(launcher, account, null, COMPOSE, null, null);
+        launch(launcher, account, null, COMPOSE, null, null, null, null);
     }
 
     /**
      * Can be called from a non-UI thread.
      */
     public static void composeToAddress(Context launcher, Account account, String toAddress) {
-        launch(launcher, account, null, COMPOSE, toAddress, null);
+        launch(launcher, account, null, COMPOSE, toAddress, null, null, null);
+    }
+
+    /**
+     * Can be called from a non-UI thread.
+     */
+    public static void composeWithQuotedText(Context launcher, Account account,
+            String quotedText, String subject) {
+        launch(launcher, account, null, COMPOSE, null, null, quotedText, subject);
     }
 
     /**
@@ -340,30 +355,31 @@
      * Can be called from a non-UI thread.
      */
     public static void reply(Context launcher, Account account, Message message) {
-        launch(launcher, account, message, REPLY, null, null);
+        launch(launcher, account, message, REPLY, null, null, null, null);
     }
 
     /**
      * Can be called from a non-UI thread.
      */
     public static void replyAll(Context launcher, Account account, Message message) {
-        launch(launcher, account, message, REPLY_ALL, null, null);
+        launch(launcher, account, message, REPLY_ALL, null, null, null, null);
     }
 
     /**
      * Can be called from a non-UI thread.
      */
     public static void forward(Context launcher, Account account, Message message) {
-        launch(launcher, account, message, FORWARD, null, null);
+        launch(launcher, account, message, FORWARD, null, null, null, null);
     }
 
     public static void reportRenderingFeedback(Context launcher, Account account, Message message,
             String body) {
-        launch(launcher, account, message, FORWARD, "android-gmail-readability@google.com", body);
+        launch(launcher, account, message, FORWARD,
+                "android-gmail-readability@google.com", body, null, null);
     }
 
     private static void launch(Context launcher, Account account, Message message, int action,
-            String toAddress, String body) {
+            String toAddress, String body, String quotedText, String subject) {
         Intent intent = new Intent(launcher, ComposeActivity.class);
         intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
         intent.putExtra(EXTRA_ACTION, action);
@@ -379,6 +395,12 @@
         if (body != null) {
             intent.putExtra(EXTRA_BODY, body);
         }
+        if (quotedText != null) {
+            intent.putExtra(EXTRA_QUOTED_TEXT, quotedText);
+        }
+        if (subject != null) {
+            intent.putExtra(EXTRA_SUBJECT, subject);
+        }
         launcher.startActivity(intent);
     }
 
@@ -398,6 +420,7 @@
         Message message;
         ArrayList<AttachmentPreview> previews;
         mShowQuotedText = false;
+        CharSequence quotedText = null;
         int action;
         // Check for any of the possibly supplied accounts.;
         Account account = null;
@@ -408,6 +431,7 @@
 
             previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
             mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
+            quotedText = savedState.getCharSequence(EXTRA_QUOTED_TEXT);
         } else {
             account = obtainAccount(intent);
             action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
@@ -460,6 +484,11 @@
             initQuotedTextFromRefMessage(mRefMessage, action);
             showCcBcc(savedState);
             mShowQuotedText = message.appendRefMessageContent;
+            // if we should be showing quoted text but mRefMessage is null
+            // and we have some quotedText, display that
+            if (mShowQuotedText && quotedText != null && mRefMessage == null) {
+                initQuotedText(quotedText, false /* shouldQuoteText */);
+            }
         } else if (action == EDIT_DRAFT) {
             initFromDraftMessage(message);
             boolean showBcc = !TextUtils.isEmpty(message.getBcc());
@@ -589,9 +618,6 @@
 
     private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
         setFocus(action);
-        if (action == COMPOSE) {
-            mQuotedTextView.setVisibility(View.GONE);
-        }
         // Don't bother with the intent if we have procured a message from the
         // intent already.
         if (!hadSavedInstanceStateMessage(savedInstanceState)) {
@@ -797,6 +823,10 @@
 
         if (mRefMessage != null) {
             state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
+        } else if (message.appendRefMessageContent) {
+            // If we have no ref message but should be appending
+            // ref message content, we have orphaned quoted text. Save it.
+            state.putCharSequence(EXTRA_QUOTED_TEXT, mQuotedTextView.getQuotedTextIfIncluded());
         }
         state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
         state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
@@ -1292,6 +1322,8 @@
                     mSubject.setText(value);
                 } else if (EXTRA_BODY.equals(extra)) {
                     setBody(value, true /* with signature */);
+                } else if (EXTRA_QUOTED_TEXT.equals(extra)) {
+                    initQuotedText(value, true /* shouldQuoteText */);
                 }
             }
         }
@@ -1302,9 +1334,12 @@
             if (text != null) {
                 setBody(text, true /* with signature */);
             }
+
+            // TODO - support EXTRA_HTML_TEXT
         }
     }
 
+
     @VisibleForTesting
     protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
         // TODO: handle the case where there are spaces in the display name as
@@ -1501,6 +1536,10 @@
         }
     }
 
+    private void initQuotedText(CharSequence quotedText, boolean shouldQuoteText) {
+        mQuotedTextView.setQuotedTextFromHtml(quotedText, shouldQuoteText);
+        mShowQuotedText = true;
+    }
 
     private void initQuotedTextFromRefMessage(Message refMessage, int action) {
         if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
@@ -1744,16 +1783,19 @@
                         mAccount.getReplyFroms());
     }
 
-    private void setSubject(Message refMessage, int action) {
-        String subject = refMessage.subject;
+    /**
+     * Returns a formatted subject string with the appropriate prefix for the action type.
+     * E.g., "FWD: " is prepended if action is {@link ComposeActivity#FORWARD}.
+     */
+    public static String buildFormattedSubject(Resources res, String subject, int action) {
         String prefix;
         String correctedSubject = null;
         if (action == ComposeActivity.COMPOSE) {
             prefix = "";
         } else if (action == ComposeActivity.FORWARD) {
-            prefix = getString(R.string.forward_subject_label);
+            prefix = res.getString(R.string.forward_subject_label);
         } else {
-            prefix = getString(R.string.reply_subject_label);
+            prefix = res.getString(R.string.reply_subject_label);
         }
 
         // Don't duplicate the prefix
@@ -1761,10 +1803,15 @@
                 && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
             correctedSubject = subject;
         } else {
-            correctedSubject = String
-                    .format(getString(R.string.formatted_subject), prefix, subject);
+            correctedSubject = String.format(
+                    res.getString(R.string.formatted_subject), prefix, subject);
         }
-        mSubject.setText(correctedSubject);
+
+        return correctedSubject;
+    }
+
+    private void setSubject(Message refMessage, int action) {
+        mSubject.setText(buildFormattedSubject(getResources(), refMessage.subject, action));
     }
 
     private void initRecipients() {
@@ -2085,7 +2132,7 @@
         }
 
         /**
-         * Use the {@link ContentResolver#call()} method to send or save the message.
+         * Use the {@link ContentResolver#call} method to send or save the message.
          *
          * If this was successful, this method will return an non-null Bundle instance
          */
diff --git a/src/com/android/mail/compose/QuotedTextView.java b/src/com/android/mail/compose/QuotedTextView.java
index bb9ac75..8ebac6f 100644
--- a/src/com/android/mail/compose/QuotedTextView.java
+++ b/src/com/android/mail/compose/QuotedTextView.java
@@ -248,7 +248,7 @@
     public void setQuotedText(int action, Message refMessage, boolean allow) {
         setVisibility(View.VISIBLE);
         String htmlText = getHtmlText(refMessage);
-        StringBuffer quotedText = new StringBuffer();
+        StringBuilder quotedText = new StringBuilder();
         DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
         Date date = new Date(refMessage.dateReceivedMs);
         Resources resources = getContext().getResources();
@@ -299,6 +299,26 @@
         allowRespondInline(true);
     }
 
+    public void setQuotedTextFromHtml(CharSequence htmlText, boolean shouldQuoteText) {
+        setVisibility(VISIBLE);
+        if (shouldQuoteText) {
+            final StringBuilder quotedText = new StringBuilder();
+            final Resources resources = getContext().getResources();
+            quotedText.append(sQuoteBegin);
+            quotedText.append(
+                    String.format(resources.getString(R.string.forward_attribution_no_headers)));
+            quotedText.append(HEADER_SEPARATOR);
+            quotedText.append(BLOCKQUOTE_BEGIN);
+            quotedText.append(htmlText);
+            quotedText.append(BLOCKQUOTE_END);
+            quotedText.append(QUOTE_END);
+            setQuotedText(quotedText);
+        } else {
+            setQuotedText(htmlText);
+        }
+        findViewById(R.id.divider_bar).setVisibility(GONE);
+        findViewById(R.id.quoted_text_button_bar).setVisibility(GONE);
+    }
     /**
      * Set quoted text. Some use cases may not want to display the check box (i.e. forwarding) so
      * allow control of that.
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 9aadf87..6013769 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -2108,7 +2108,8 @@
     private static boolean getShouldAllowDrawerPull(final int viewMode) {
         // if search list/conv mode, disable drawer pull
         // allow drawer pull everywhere except conversation mode where the list is hidden
-        return !ViewMode.isSearchMode(viewMode) && !(ViewMode.isConversationMode(viewMode));
+        return !ViewMode.isSearchMode(viewMode) && !ViewMode.isConversationMode(viewMode) &&
+                !ViewMode.isAdMode(viewMode);
 
         // TODO(ath): get this to work to allow drawer pull in 2-pane conv mode.
     /* && !isConversationListVisible() */