ComposeActivity.java revision 6d2442ba4417717b2a19714b0ac28c7265872ba3
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/**
28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc.
38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License.
68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at
78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software
118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and
148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License.
158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */
168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose;
188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener;
215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
252558b509117872e539a6eaeb72aa63425529d50bTony Mantlerimport android.app.DialogFragment;
26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment;
27b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction;
2896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager;
296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
3296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader;
3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader;
3682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
398e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor;
431ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable;
4482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
47ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString;
4882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
49c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
5082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
5146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
52c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
533cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity;
5462d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent;
55326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
56b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
58b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
62b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection;
6362d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo;
64326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
658e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
66433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
68013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
697b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
70c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
715c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
725680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService;
735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
741ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView;
7540882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
769932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
775a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
7933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
8130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
825680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
843ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8692551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
87181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
8830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
893ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
9012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
911ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
93fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
94b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
96434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
97febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
98b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
9930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
10030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
10146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1048e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
10946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
110bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
11146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1151c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
116bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
11782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
11846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
11946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1202558b509117872e539a6eaeb72aa63425529d50bTony Mantler        RespondInlineListener, TextWatcher,
121a990a715012379451344246c5156d29938f12886Alice Yang        AttachmentAddedOrDeletedListener, OnAccountChangedListener,
122a990a715012379451344246c5156d29938f12886Alice Yang        LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
123a990a715012379451344246c5156d29938f12886Alice Yang        FeedbackEnabledActivity {
1246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
12515f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int COMPOSE = -1;
12615f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY = 0;
12715f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY_ALL = 1;
12815f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int FORWARD = 2;
12915f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int EDIT_DRAFT = 3;
1306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
13296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
134326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
135326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1361623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1371d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
138a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
147d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1489a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
14962066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
15062066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
16482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
16682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
16882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
16982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
17082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1711f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
1736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1766349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
179daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
181e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
182f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1835680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    /** If set, we will clear notifications for this folder. */
1845680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder";
1855680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
1863ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
18736bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
188b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
189b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
190b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
191434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
192bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
193bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
195b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
196013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
197013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
198013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
200e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
2018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
202e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
203e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
204e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
205e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_END = null;
206e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
20796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
208b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
209a990a715012379451344246c5156d29938f12886Alice Yang    private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
21047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
211b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2122db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2132db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2159f855d667e34fbf0d330845225c26956e540b819Andy Huang    private static final String KEY_INNER_SAVED_STATE = "compose_state";
2169f855d667e34fbf0d330845225c26956e540b819Andy Huang
21782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
21882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
21982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
22082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
221c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
222c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
223c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2267b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
22733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
22892551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
229181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
23082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
233326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
234326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
23546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
23646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
23746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
238433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2391a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2402eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
241eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2421883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2431883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
244013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
245eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
24782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
24882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
24982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
250b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
251b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
25444a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
25693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
25793b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2583ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
259326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
260daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
261daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
262daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
263cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
264cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
265cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
266b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
267a990a715012379451344246c5156d29938f12886Alice Yang    private boolean mShowQuotedText = false;
2689f855d667e34fbf0d330845225c26956e540b819Andy Huang    private Bundle mInnerSavedState;
269daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
270daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2711623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2721623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2731623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2741623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2751623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2761623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2771623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2781623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2801623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
2811623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
282daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
283326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
284326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2853ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
2861ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, EDIT_DRAFT, null, null);
287326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
288326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
29233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2931ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, null, COMPOSE, null, null);
2946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2986349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2993de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    public static void composeToAddress(Context launcher, Account account, String toAddress) {
3003de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein        launch(launcher, account, null, COMPOSE, toAddress, null);
3013de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    }
3023de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein
3033de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    /**
3043de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     * Can be called from a non-UI thread.
3053de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     */
3060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
3070aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
3080aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
3090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3110aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3140aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3150aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3160aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3170aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3180aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3190aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3200aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3210aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3220aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3236d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        updateActionIntent(account, messageUri, action, intent);
3246d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3256d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        return intent;
3266d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    }
3276d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3286d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    @VisibleForTesting
3296d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    static Intent updateActionIntent(Account account, Uri messageUri, int action, Intent intent) {
3300aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3310aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3320aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3330aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3360aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3370aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3380aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3390aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
3421ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, REPLY, null, null);
3436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3483ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
3491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, REPLY_ALL, null, null);
3506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3553ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
3561ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, FORWARD, null, null);
3576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3591ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    public static void reportRenderingFeedback(Context launcher, Account account, Message message,
3601ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String body) {
3611ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, FORWARD, "android-gmail-readability@google.com", body);
3621ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    }
3631ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
3641ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    private static void launch(Context launcher, Account account, Message message, int action,
3651ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String toAddress, String body) {
3666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
370bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
371bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
372bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
373bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
374bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
3751ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (toAddress != null) {
3761ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_TO, toAddress);
3771ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3781ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (body != null) {
3791ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_BODY, body);
3801ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
3826349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3838e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
3848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
3858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
3868e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
3878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
3889f855d667e34fbf0d330845225c26956e540b819Andy Huang        mInnerSavedState = (savedInstanceState != null) ?
3899f855d667e34fbf0d330845225c26956e540b819Andy Huang                savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
390b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
391b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
392b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
393b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
3949f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle savedState = mInnerSavedState;
39546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
396818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
397e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
39862066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
399a990a715012379451344246c5156d29938f12886Alice Yang        mShowQuotedText = false;
400e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
40147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
40247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
4039f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (hadSavedInstanceStateMessage(savedState)) {
4049f855d667e34fbf0d330845225c26956e540b819Andy Huang            action = savedState.getInt(EXTRA_ACTION, COMPOSE);
4059f855d667e34fbf0d330845225c26956e540b819Andy Huang            account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
4069f855d667e34fbf0d330845225c26956e540b819Andy Huang            message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
40762066e47fe69c33b60ed970e46809ba81d044064Mark Wei
4089f855d667e34fbf0d330845225c26956e540b819Andy Huang            previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
4099f855d667e34fbf0d330845225c26956e540b819Andy Huang            mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
410e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
41147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
412e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
413e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
414e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
41562066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
416e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
417b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
418e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
41962066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
42092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
42192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
422818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
423818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
424818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
425bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
426fe853d3427119202562519c2add6873590851705Scott Kennedy        initRecipients();
427fe853d3427119202562519c2add6873590851705Scott Kennedy
4285680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
4295680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
4305680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
4315680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4325680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4335680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
434d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
43548cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
43648cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder);
4375680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4385680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4395680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4405680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
441daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
442daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
443daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
444daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
445daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
446daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
447daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
448daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
449daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
450daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
451daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
45296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
453a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = true;
454a990a715012379451344246c5156d29938f12886Alice Yang            mComposeMode = action;
455a990a715012379451344246c5156d29938f12886Alice Yang            getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
45696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
45796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
458e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
459e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
4609f855d667e34fbf0d330845225c26956e540b819Andy Huang            showCcBcc(savedState);
461a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
462e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
463e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
4648960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
4658960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
466ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
467bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
468bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
469bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
470bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
471bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
472bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
473bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
474bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
475bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
476bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
477bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
478bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
479bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
480bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
481bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
482bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
483a990a715012379451344246c5156d29938f12886Alice Yang            LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
484a990a715012379451344246c5156d29938f12886Alice Yang
485a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
486a990a715012379451344246c5156d29938f12886Alice Yang            if (message.refMessageUri != null) {
487a990a715012379451344246c5156d29938f12886Alice Yang                // If we're editing an existing draft that was in reference to an existing message,
488a990a715012379451344246c5156d29938f12886Alice Yang                // still need to load that original message since we might need to refer to the
489a990a715012379451344246c5156d29938f12886Alice Yang                // original sender and recipients if user switches "reply <-> reply-all".
490a990a715012379451344246c5156d29938f12886Alice Yang                mRefMessageUri = message.refMessageUri;
491a990a715012379451344246c5156d29938f12886Alice Yang                mComposeMode = action;
492a990a715012379451344246c5156d29938f12886Alice Yang                getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
493a990a715012379451344246c5156d29938f12886Alice Yang                return;
494a990a715012379451344246c5156d29938f12886Alice Yang            }
495e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
496e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
4970aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
498a990a715012379451344246c5156d29938f12886Alice Yang                mShowQuotedText = true;
499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
5008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
5018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
502bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
503a990a715012379451344246c5156d29938f12886Alice Yang
504a990a715012379451344246c5156d29938f12886Alice Yang        mComposeMode = action;
5059f855d667e34fbf0d330845225c26956e540b819Andy Huang        finishSetup(action, intent, savedState);
50696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
507bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
508b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
509faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
510faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
511b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
512b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
513faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
514b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
515b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
516b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
51726d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
518b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
519faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
520dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
521b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
522b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
523b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
524b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
525b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
526b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
527b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
528b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
529b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
530b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
531faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
532b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
533b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
534b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
535b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
53647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
53747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
53847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
53947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
54047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
54147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
54247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
5437ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
5447ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
5457ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
5467ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
5477ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
5487ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
54947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
5505ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
5515ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
5525ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
55347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
55447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
5550617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
5560617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
5570617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
5580617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
5590617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
56047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
56147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
56247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
56347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
564b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
56547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
56647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
56747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
568b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
56947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
57047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
57147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
57247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
57347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
57447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
57547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
576b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
57747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
57847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
57947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
58047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
581b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
582b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
583b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
58447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
58547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
58647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
58747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
58847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
589a990a715012379451344246c5156d29938f12886Alice Yang    private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
59034a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
591bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
592eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
59346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
594f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
595f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
596f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
597f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
598f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
599a990a715012379451344246c5156d29938f12886Alice Yang        initActionBar();
600e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
601e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
602d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
603d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
604d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
605d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
606d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
607d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
608d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
60975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
610326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
611a990a715012379451344246c5156d29938f12886Alice Yang        updateHideOrShowQuotedText(mShowQuotedText);
6121623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
6139f855d667e34fbf0d330845225c26956e540b819Andy Huang        mRespondedInline = mInnerSavedState != null ?
6149f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
6151623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
6161623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
6171623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
61871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
61971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
620ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) {
621f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
622f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
623f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
62471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
62571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
62640882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
627433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
628433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
629433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
630433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
631433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
632433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
633433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
634433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
635433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
636433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
637433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
638433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
639433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
640433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
641433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
642433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
643433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
644433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
645433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
646433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
6472708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
6482708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
6492708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
6502708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
651ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                //$FALL-THROUGH$
652433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
653433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
654433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
655433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
656433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
657433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
658433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
659433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
660433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
661433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
662433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
663433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
664433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
665433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
666433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
667433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
668433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
669433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
670433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
671433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
6728743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
673433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
674433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
675433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
6761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6771a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
6781a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
6791a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
6801a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
6811a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
6821a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
683818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
684c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromSpinner.initialize(mComposeMode, mAccount, mAccounts, mRefMessage);
685818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
6861a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6871a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
688eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
689eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
690eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
691eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
692a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
6933d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
6943d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
695a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
696a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
697eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
698eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
699eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
700eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
701b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
702eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
703b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
704b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
705a990a715012379451344246c5156d29938f12886Alice Yang            // We were waiting for the user to create an account
706b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
707b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
708b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
709b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
710b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
711b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
712b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
713b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
714eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
715eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
716eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
717eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
718e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
7197bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        final boolean hasAccounts = mAccounts != null && mAccounts.length > 0;
7207bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7217bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            clearChangeListeners();
7227bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
723e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
7249f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (mInnerSavedState != null) {
7259f855d667e34fbf0d330845225c26956e540b819Andy Huang            if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
7269f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
7279f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
728e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
729e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
730e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
731e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
732e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
733e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
734e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
735e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
736e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7377bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7387bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            initChangeListeners();
7397bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
740e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
741e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
742e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
743eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
744eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
7459f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle inner = new Bundle();
7469f855d667e34fbf0d330845225c26956e540b819Andy Huang        saveState(inner);
7479f855d667e34fbf0d330845225c26956e540b819Andy Huang        state.putBundle(KEY_INNER_SAVED_STATE, inner);
7489f855d667e34fbf0d330845225c26956e540b819Andy Huang    }
7499f855d667e34fbf0d330845225c26956e540b819Andy Huang
7509f855d667e34fbf0d330845225c26956e540b819Andy Huang    private void saveState(Bundle state) {
751b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
752b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
753b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
754b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
755e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
756e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
757e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
758e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
760e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
761e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
762e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
763e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7646273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
7656273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
766151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
767d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
768d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
769d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
770e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
771e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
772e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
773e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
774e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
776e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
777eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
778e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
779e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
780e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
781e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
782e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
783e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
784e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
785e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
786e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
787e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
789e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
7901f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
791e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
792e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
793e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
7941f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
795e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
799e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
800326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
801326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
8021623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
803816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
80462066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
80562066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
806e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
807e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
808e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
809e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
811e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
812e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
813e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
814e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
815e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
816e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
820e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
821d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
824e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
825e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
8268960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8278960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8288960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
8298960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
830e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
831b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
832b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
833e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
834e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
835e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
836a990a715012379451344246c5156d29938f12886Alice Yang        message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
837e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
838e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
839e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
840e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
841e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
842e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
843e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
8488960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
8498960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
8501f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
8518960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8528960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8538960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
854e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
8551f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
8561f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
857ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static String formatSenders(final String string) {
8583c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
8593c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
8603c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
8613c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
8623c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
8633c9115813343861a44133b805fb9f55512d20948Mindy Pereira
864818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
865818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
866bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
867bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
868bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
86923e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
87023e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
871b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
872b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
87323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
874fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
875f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal            MailActivity.setNfcMessage(mAccount.name);
876fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
877818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
878818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
879e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
880e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
88162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
88262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
883c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook        mFromSpinner.initialize(action, mAccount, mAccounts, mRefMessage);
884c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook
8859a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
8869a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
8879a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
8889a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
8899a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
890c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook                final String accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
8919a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
8929a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
893e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
894e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
895e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
896e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
897e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
898e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
899e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
90062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
90162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
902238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
90362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
9049a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
90562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
9069a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
90762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
908a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
909a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
91062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
91162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
912c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
91362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
914a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
915a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
916c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
917a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
918a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
91946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
92046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
92162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
92262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
92362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
92462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
92562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
92662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
92762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
92962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
93062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
93162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
93262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
93362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
93462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
93562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
93662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
93762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
93862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
93962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
94062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
94162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
94262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
94362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
94562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
946326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
94762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
94989bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
95062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
95162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
95262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
9535ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getToAddresses()));
9545ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getCcAddresses()));
95562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
95662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
95762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
95862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
95962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
96062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
96162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
96262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
96462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
96562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
96762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
96962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
97062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
97162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
97262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
97362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
97462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
97562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
97662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
97762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
9781617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
9791617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
9801617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
9811617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
9821617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
9831617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
98462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
98562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
98662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
98762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
98862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
98962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
99062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
99162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
99262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
993ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) {
994ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final ReplyFromAccount from : account.getReplyFroms()) {
99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
99662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
99862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
999cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
1000cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
100162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
100262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1003e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
10048960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
100562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
100662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
100762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
100862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
1009cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
101062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
101162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
101262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
101362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
101462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
101562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
101662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
101762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
101862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
101962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
102062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
102146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
1022b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
1023a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
10248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
10258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
10268e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
10278e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
10287b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
102993b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
1030cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
1031cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
1032cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
103393b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
1034cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
1035cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
1036cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
1037818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
103841500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mTo.setTokenizer(new Rfc822Tokenizer());
1039818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
104041500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mCc.setTokenizer(new Rfc822Tokenizer());
1041818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
104241500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mBcc.setTokenizer(new Rfc822Tokenizer());
104382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
104482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
10456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
104662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
104746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
104846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
1049433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
10501a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
10512eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1052eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
10535a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1054326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1055326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
105662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
105762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
105862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
105962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
106062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
106162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
106262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
106362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
106462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1065e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1066e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1067e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1068e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1069e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1070e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1071e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1072e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1073e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1074e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1075cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1076cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1077cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1078cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1079cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1080cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1081cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1082cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1083cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1084cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
108575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
108675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
108775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
108875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
10891d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
10901d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
109175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
109275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1093cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1094cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1095cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1096cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1097cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1098cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1099cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1100cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1101cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1102cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1103cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1104cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
110575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1106818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
110775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
110875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1109a990a715012379451344246c5156d29938f12886Alice Yang    private void initActionBar() {
1110a990a715012379451344246c5156d29938f12886Alice Yang        LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
1111eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1112e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1113e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1114e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1115a990a715012379451344246c5156d29938f12886Alice Yang        if (mComposeMode == ComposeActivity.COMPOSE) {
1116eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1117eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1118326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1119eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1120326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1121326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1122326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1123eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1124eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1125a990a715012379451344246c5156d29938f12886Alice Yang            switch (mComposeMode) {
1126326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1127eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1128326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1129326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1130eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1131326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1132326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1133eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1134326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1135326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
11366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1137fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1138fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1139fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
11406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
11416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
11420aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
11430aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
11441ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
11451ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // Check if To: address and email body needs to be prefilled based on extras.
11461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // This is used for reporting rendering feedback.
11471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
11481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            Intent intent = getIntent();
11491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            if (intent.getExtras() != null) {
11501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String toAddresses = intent.getStringExtra(EXTRA_TO);
11511ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (toAddresses != null) {
11521ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
11531ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11541ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String body = intent.getStringExtra(EXTRA_BODY);
11551ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (body != null) {
11561ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    setBody(body, false /* withSignature */);
11571ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11581ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            }
11591ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
11601ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
116196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
116296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
116396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
116496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
116529a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
116696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
116796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
116896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
116996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
117096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
117196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
11720aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
11748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
11758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
11768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
11778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11780aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1179e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
11808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
11818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
11826349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1183c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1184c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1185e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
11861f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1187bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1188bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1189bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1190bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1191bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
1192bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
1193bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
1194bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
1195bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
11962421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
11972421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
11982421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
11995c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
12002421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
12012421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1202cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1203002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1204bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1205002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1206bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1207752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1208002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1209752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1210752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1211752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1212c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1213c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1214752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1215752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1216752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
12171a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1218c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1219002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1220002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1221bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1222752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1223752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1224752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1225752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1226752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1227002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1228752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1229752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1230002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1231002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1232002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1233002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
12343971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1235bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1236bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1237bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
12388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
12398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
12408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
12418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
12428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
12438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
12448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
12458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
12468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
12478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
12488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
12498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
12508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
12518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
12528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
12538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
12548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
12558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12560b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
12578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
12588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
12598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1260dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
12618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
12628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
12678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
12808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
12828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
12858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
12878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1288dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
12898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1290dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1292dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
12938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
12948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
12958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
12968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
12978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
13028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
13048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
13058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
13068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1308e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1309e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
13108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
13118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1312a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1313a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1314a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
13158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
13168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
13178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
1318a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
13197dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee            return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME);
1320a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1321a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1322a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1323a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1324a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1325a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1326a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1327a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
13288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
13317dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from
13327dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * changing '+' into ' '
13337dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     *
13347dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @param toReplace Input string
13357dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @return The string with all "+" characters replaced with "%2B"
13367dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     */
13373b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static String replacePlus(String toReplace) {
13387dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee        return toReplace.replace("+", "%2B");
13397dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    }
13407dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee
13417dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    /**
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
13448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
13468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
13508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
13518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
13528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
13538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
13548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
13568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
13588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1359a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1360a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1361a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
13778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
13788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
13808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
13818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13827dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)),
13837dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                        UTF8_ENCODING_NAME));
13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
13868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
13878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
13918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
13928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13937dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME),
13948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
13958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
13978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
14008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1401bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1402bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1403434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1404434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1405434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1406434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1407434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1408434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1409434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1410434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1411434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1412434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1413434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1414434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1415434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1416434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1417434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1418434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1419434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1420434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1421434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1422434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
14233cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1424434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
14253cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14263cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
14273cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
14283cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
14293cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
14303cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
14313cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1432434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1433434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1434434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1435434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
14363cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14373cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1438434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1439434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1440434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
14413cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
14423cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
14433cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1444eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1445eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1446f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
144703ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
144803ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
144903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
145003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1451f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1452f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1453f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1454f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1455f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1456f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1457f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1458f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1459f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1461f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1462f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1463434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1464f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1465f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1466f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1467f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
14689a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
14699a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
14709a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
14719a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
14729a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
14739a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
14749a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
14759a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
14769a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
14779a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
14789a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
14799a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
14809a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
14819a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
14829a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
14839a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
14849a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
14859a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
14869a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
14879a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
14889a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1489f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14909a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1491f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1492f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
14939a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1494f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
14959a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1496f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1497f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1498f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1499f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1500f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1501f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1502f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1503f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1504f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1505f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1506f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1507e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1508e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
15099932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
15109932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
151146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
151246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
151346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1514ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1515326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1516326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1517ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1518326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1519ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1520326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1521ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1522ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1523cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1524ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1525ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
152646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
152746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1528a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1529326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1530326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1531326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1532326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1533326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1534326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1535326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1536326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1537326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1538013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1539013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1540013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1541013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1542013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
15432421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
15442421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
15452421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
15465c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
15475c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
15482421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
15492421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1550013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
15515c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
15525c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
15535c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1554434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1555434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1556434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1557434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
15585c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
15595c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
15605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
15615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
15625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1563434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
15649932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
15659932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
15669932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1567013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
15689932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
15699932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1570434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1571013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1572013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1573013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
15740aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
15754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
15764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
15774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
15784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
1579ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        initReplyRecipients(refMessage, action);
15804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15826d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // TODO: This should be private.  This method shouldn't be used by ComposeActivityTests, as
15836d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // it doesn't setup the state of the activity correctly
1584818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
1585ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    void initReplyRecipients(final Message refMessage, final int action) {
15865ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp        String[] sentToAddresses = refMessage.getToAddresses();
1587a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
158865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        String replytoAddress = refMessage.getReplyTo();
158965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
159065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (TextUtils.isEmpty(replytoAddress)) {
159165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            replytoAddress = refMessage.getFrom();
159265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
15934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
15954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
15964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1597a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1598a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
1599ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            toAddresses = initToRecipients(refMessage.getFrom(), replytoAddress, sentToAddresses);
1600a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1601a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
16024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
1603ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            toAddresses = initToRecipients(refMessage.getFrom(), replytoAddress, sentToAddresses);
1604154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
1605ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, sentToAddresses);
1606ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, refMessage.getCcAddresses());
16074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
16084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
16124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
16134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
16168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
16178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
16184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1620bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1621bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1622bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1623bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
16244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
16254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
16264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
16274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
16284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
16308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
16344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
16354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
16378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
16388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
16428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
16438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
16448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
16458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
16468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
16478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
16484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1651ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) {
1652ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final HashSet<String> hash = new HashSet<String>();
1653ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final Rfc822Token[] tokens : list) {
16544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
16554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
16564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
16594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
16624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
16634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
16644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
16664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
16674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
16694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
16724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
16734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
16744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
16754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1678ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static void addAddressToList(final String address, final RecipientEditTextView list) {
16794a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
16804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
16814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1682ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
16834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
16854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
16864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
1690ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    protected Collection<String> initToRecipients(final String fullSenderAddress,
1691ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            final String replyToAddress, final String[] inToAddresses) {
16924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
16934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
16944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
16954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
16964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
16974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
169865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
16993ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
17004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
170165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
170265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
170365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
170465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
170565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
170665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
170765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
170865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
170965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
171065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
171165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
171265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
171365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
171465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
171565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1716fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
17171469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
17184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
17204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1722ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void addRecipients(final Set<String> recipients, final String[] addresses) {
1723ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : addresses) {
1724cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1725cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
17264a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
17275ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
17284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
17294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
173146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
173246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1733cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1734cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1735cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1736cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1737cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1738cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1739cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
17405ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
17415ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1742fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1743cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1744cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
17453ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
17463ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
174746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
174846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
174946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
175046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
175146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
175246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
175346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
175446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
175546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
175646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
175746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1758c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1759c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
176046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
176146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
176246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
176346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
176446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
176546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
176646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
176746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1768818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1769818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1770818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1771818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1772eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1773eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1774818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1775679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
177682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1777679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
177833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
177933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1780c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
178133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1782c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
178382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1784c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
178582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
17868e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
17878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
17898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
17908e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
17918e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1792a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
17938e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
17948e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1795a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
17968e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
1797cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_photo_attachment:
1798cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_PHOTO);
1799cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
1800cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_video_attachment:
1801cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_VIDEO);
1802cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
18038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
18048e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1805b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1806b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1807b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1808b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1809b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1810b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1811b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1812b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1813b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1814b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
18151d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
18161d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
18171d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
18181d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
18191d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
18201d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
18211d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
18221d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
18231d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
18241d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18251d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
18261d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
18271d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
18281d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18291d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
18301d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
183182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
18321d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
18339f855d667e34fbf0d330845225c26956e540b819Andy Huang        enableSave(mInnerSavedState != null ?
18349f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
18351d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
18361d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
18371d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
18381d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
18391d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
184082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
18413ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
18423ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
18433ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
18443ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
18453ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
18463ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
18473ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
18483ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
18493ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
18503ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1851b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1852b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1853b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1854b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1855ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1856ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1857818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1858ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1859ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1860ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1861ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1862ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1863ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1864ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1865ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1866ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1867ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1868ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1869ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1870ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1871ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1872ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1873b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1874b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
187575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1876b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
18772db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_photo_attachment:
18782db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_PHOTO);
18792db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                break;
18802db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_video_attachment:
18812db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_VIDEO);
18827b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1883ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1884ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1885b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
188633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
188748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira                doSave(true);
188833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
188933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
189033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
189175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1892efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1893efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1894efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
18951f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
18961f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
18971f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1898fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1899daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                onAppUpPressed();
1900fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1901fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
190230745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook                Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
1903fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1904fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
190517beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook                Utils.sendFeedback(this, mAccount, false);
1906fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
190775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
190875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
190933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1910b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1911b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1912b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1913326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1914b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1915b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1916b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1917b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1918b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1919b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1920b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1921b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1922b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1923b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
19241672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
19251672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
19261672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
1927daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1928daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1929daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1930daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1931daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1932daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1933daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1934daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1935daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1936daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1937daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
19380c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
1939daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1940daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1941daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1942daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1943daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1944daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
194533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
1946dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
194733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
194833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
194948e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
1950dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
195148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
195248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
1953e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1954e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
195582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
19567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
19577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
195882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
195982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
196082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1961e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1962e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
196382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
196482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1965e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1966e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1967e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
196844a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
196982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
197082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
197144a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
197282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
197382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
197482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
197544a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
197682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
197782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
197882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
197982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
19807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
198182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
198292551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
19837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
19847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
198582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
198682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
198782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
198844a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
198944a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
199082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
199182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
199282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
199382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
1994febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
1995febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
1996febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
1997febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
1998cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1999cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
2000eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
200182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
200282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
200382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
200482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
200582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
200682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
2007ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount);
200872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
200972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
201072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
201172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
201272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
201372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
201472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
201572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
201672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
201772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
201872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
201972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
202072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
202172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
202272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2023ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private void sendOrSaveMessage(final long messageIdToSave,
2024ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) {
202572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
202672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
202772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
202872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
202972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
203072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
203172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
20333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
20343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
20353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2036013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
20373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
203872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
2039013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
20403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
20413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
20423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
20433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
20443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
20453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
20463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
20473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
20483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
20493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
20503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
20513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
20523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
20533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
20543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
20553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
20563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
20573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
20583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
20593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
20603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
20613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
20623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
206372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
20643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
20653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
20663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
20673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
20693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2070ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) {
20713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
20723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
20733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
2074ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                for (final String key : keys) {
20753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
20763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2077ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
20783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
20793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
20803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2081ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
20827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
20837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
208482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
208572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
208682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
208772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
208872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Use the {@link ContentResolver#call()} method to send or save the message.
208972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
209072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
209172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2092ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle callAccountSendSaveMethod(final ContentResolver resolver,
2093ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final Account account, final String method,
2094ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage) {
209572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
209672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
209772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
209872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
209972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
210072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
210172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
210272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
210372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
210472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
210572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
210672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
210772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
210872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
210972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
211072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
211172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
211272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
211372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
211482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
211572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
21163c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
21173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
21183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
21193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
21203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
21213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
212372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
212482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
212682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2127e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2128e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
212992551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
21313ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2132e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2133e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
213482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
21353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
213682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
21383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
213982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
214082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
214182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
214282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
214382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
21443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
214682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
214782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
214882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
214982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
215082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
21513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
21533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
21543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
21553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
21573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
21583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
21593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
21603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
2161ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle initializeAttachmentFds(final Context context,
2162ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final List<Attachment> attachments) {
21633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
21643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
21653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
21683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
21693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
21713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
21723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
21733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
21763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
21773c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
21783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
21793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
21803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2181c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2182c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2183c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2184c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2185c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2186c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2187c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2188c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2189c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2190c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2191c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2192c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2193c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
21943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
21973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
21983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
22023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
220782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
221382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
222082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
222182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
222382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
222782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
222982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
223082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
223182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
223282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
223382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
223582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
223682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
223782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
223982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
224182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
224282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
224382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2244ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) {
2245e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2246e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2247e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
2248ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : to) {
224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
225482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22552558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class RecipientErrorDialogFragment extends DialogFragment {
22562558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static RecipientErrorDialogFragment newInstance(final String message) {
22572558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final RecipientErrorDialogFragment frag = new RecipientErrorDialogFragment();
22582558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(1);
22592558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putString("message", message);
22602558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
22612558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
22622558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
22632558b509117872e539a6eaeb72aa63425529d50bTony Mantler
22642558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
22652558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
22662558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final String message = getArguments().getString("message");
22672558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity()).setMessage(message).setTitle(
22682558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    R.string.recipient_error_dialog_title)
22692558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
22702558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(
22712558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            R.string.ok, new Dialog.OnClickListener() {
22722558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        @Override
22732558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        public void onClick(DialogInterface dialog, int which) {
22742558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            ((ComposeActivity)getActivity()).finishRecipientErrorDialog();
22752558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        }
22762558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    }).create();
22772558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
22782558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
22792558b509117872e539a6eaeb72aa63425529d50bTony Mantler
22802558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishRecipientErrorDialog() {
22812558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // after the user dismisses the recipient error
22822558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // dialog we want to make sure to refocus the
22832558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // recipient to field so they can fix the issue
22842558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // easily
22852558b509117872e539a6eaeb72aa63425529d50bTony Mantler        if (mTo != null) {
22862558b509117872e539a6eaeb72aa63425529d50bTony Mantler            mTo.requestFocus();
22872558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
22882558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
22892558b509117872e539a6eaeb72aa63425529d50bTony Mantler
229082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
229182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
229282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
229382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
22942558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showRecipientErrorDialog(final String message) {
22952558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = RecipientErrorDialogFragment.newInstance(message);
22962558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "recipient error");
229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
229882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
229982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
230182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
230282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2303eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
230482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
230582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
230682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
230782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
230882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
230982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
231082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
231182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
231282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
23137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
231482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
231582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
231682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
231782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2318a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2319d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2320a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
232182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
232282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
232382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
232482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2325bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
232682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
232782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
232882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
232982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2330bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2331bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2332bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2333bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2334bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2335bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2336bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2337bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2338bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2339bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2340bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2341bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2342bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2343bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2344bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2345bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2346bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2347bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2348bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2349bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2350bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2351bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2352bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2353bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2354bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2355bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2356bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2357bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2358bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2359bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
236082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
236182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
236282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
236382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
236482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
236582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
236682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
236782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2368eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
236982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
237033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
237133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
237282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2378dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2379009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2380009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2381dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2382dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2383dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2384009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2385009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2386009b3712ff1657fa839049826451321fdd938d32Mark Wei
2387ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final String[] to, cc, bcc;
2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2418181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
24222558b509117872e539a6eaeb72aa63425529d50bTony Mantler                boolean emptyBody = TextUtils.getTrimmedLength(mBodyView.getEditableText()) == 0;
2423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2424181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2425181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2426181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2427181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2428181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2429181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2430181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2431181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2432181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
24332558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, save,
24342558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2436181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
24392558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, save,
24402558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2441181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2443181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
24462558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showSendConfirmDialog(R.string.confirm_send_message, save, showToast);
2447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2450181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
24512558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
2452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
24585c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2459181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2460181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2461181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2462181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2466181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2467181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
24742558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class SendConfirmDialogFragment extends DialogFragment {
24752558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static SendConfirmDialogFragment newInstance(final int messageId,
24762558b509117872e539a6eaeb72aa63425529d50bTony Mantler                final boolean save, final boolean showToast) {
24772558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final SendConfirmDialogFragment frag = new SendConfirmDialogFragment();
24782558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(3);
24792558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putInt("messageId", messageId);
24802558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("save", save);
24812558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("showToast", showToast);
24822558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
24832558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
2484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
24852558b509117872e539a6eaeb72aa63425529d50bTony Mantler
24862558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
24872558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
24882558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final int messageId = getArguments().getInt("messageId");
24892558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean save = getArguments().getBoolean("save");
24902558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast = getArguments().getBoolean("showToast");
24912558b509117872e539a6eaeb72aa63425529d50bTony Mantler
24922558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
24932558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(messageId)
24942558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setTitle(R.string.confirm_send_title)
24952558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
24962558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.send,
24972558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
24982558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int whichButton) {
24992558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).finishSendConfirmDialog(save,
25002558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                            showToast);
25012558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
25022558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
25032558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
25042558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
25052558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
25062558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25072558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishSendConfirmDialog(final boolean save, final boolean showToast) {
25082558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
25092558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
25102558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25112558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showSendConfirmDialog(final int messageId, final boolean save,
25122558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast) {
25132558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = SendConfirmDialogFragment.newInstance(messageId, save,
25142558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showToast);
25152558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "send confirm");
2516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2517181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2520181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2525181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2526181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2527181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2528181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2529181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2530181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2531181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2532181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2533181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2534181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2535181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2536181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2539e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
254005b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
254144a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
254244a6339dd80f4b5b9e5d54567021698d92467c5emindyp            ReplyFromAccount draftAccount) {
2543b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
254429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2545b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2546c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2547e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2548e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2549e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
255029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
25518960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
255292551d057965689f1952faeb06763f0762bc717fMindy Pereira
2553e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2554b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2555b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
255605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
255729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
255829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
255929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2560e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2561e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2562e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2563e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
256455271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
256555271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
256655271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
256712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2568e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
256929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2570e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2571e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2572e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2573e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
257429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
257529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2576002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
257712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2578c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2579c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2580c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2581c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2582c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2583c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2584c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2585c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2586c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2587c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2588c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2589c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2590c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2591e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
259212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
259312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
259412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
25953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
25963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
259744a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
259844a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
259982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2601181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2603181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
260482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
260782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2608b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2609b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2610b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2611b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2612b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2613b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2614b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2615b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2616b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2617b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2618002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2619002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2620002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2621002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2622002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2623002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2624002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2625002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2626002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2627002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2628002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2629002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2630002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2631002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2632002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2633002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2634002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2635002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2636002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
26372558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void sendOrSave(final boolean save, final boolean showToast) {
2638181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2639181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
26403ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2641181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2642181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
264382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26442558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final Spanned body = mBodyView.getEditableText();
26452558b509117872e539a6eaeb72aa63425529d50bTony Mantler
2646181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
26471f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
264882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
264982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26500bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
265182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2652181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2653181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2654181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2655181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2656181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2657181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2660181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2661181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2662181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2664181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
266682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26670bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
26697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2670181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
267144a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2672181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2673181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
26747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
26757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
26767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2677181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2678181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
26817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2682181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
268482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26850bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26867ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
26877ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
26887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
26897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
269182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26920bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
269447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
269547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
269647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
269747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
26987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
26997ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
27007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
27017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
27027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
27037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
27047ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
27057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
27067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
27077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
270882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
27107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
27117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
27127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
27137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
27147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
271582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
27177ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
27187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
27197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
27207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
27217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
27227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
27237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
272792551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
2728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
2729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
2730181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
2731181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
273292551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
2733181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
2734181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2735181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2736181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2737181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2739181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2740181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2741181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2742181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2743e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
274405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
274505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
274644a6339dd80f4b5b9e5d54567021698d92467c5emindyp                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount);
2747181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
2749181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
2750181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2751b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
2752181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2753181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2754181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2755181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2756181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2757181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2758181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2759181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2760181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2761181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2762181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2763181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2764181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2765181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2766181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2767181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2768181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2769181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2770181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2771181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2773181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2775181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2776181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2777181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2778181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2779181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
278082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27812db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2782013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2783013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2784d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
27852db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2786013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2787181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2788181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2789013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2790013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2791ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2792a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2793ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2794cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2795ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2796ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2797ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2798326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2799326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2800a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2801326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2802326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2803326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2804326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2805326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2806326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2807326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2808cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2809a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2810154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
281168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
28120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
28138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2814ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2815ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2816ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2817ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2818ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
28198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2820ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2821ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
28228960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
28238960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
282468c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
282568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
28269b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
282768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2828ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2829ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2830a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2831ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2832cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2833326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2834326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2835326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2836b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2837b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2838154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2839154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2840154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2841154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2842154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2843154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2844154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2845154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2846154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2847154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2848154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2849154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2850154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2851154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2852154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2853154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2854154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2855154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2856154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2857154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2858154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2859154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2860326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2861326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2862326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2863326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2864326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2865326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2866326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2867326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2868326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2869326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2870326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2871326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2872326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2873326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2874326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2875326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2876326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2877326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2878326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2879326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2880326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2881326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2882326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2883326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2884326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
288546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
288646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
288746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
288846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
288940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
28901623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
289109dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
28928654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
289309dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
289446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
289546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
289646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
289746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
289846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
289946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
290046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
290146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
290246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
290346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2904eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
290546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
290646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
290746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
290846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
290946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
291046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
291146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
291246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
291346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2914bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
291546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
291646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
291746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
291846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2919eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2920bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2921bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2922bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2923bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2924bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2925bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2926b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2927433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
29282708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
29292708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
2930b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
29312708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
2932b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2933b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2934b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2935b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2936b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2937433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2938433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2939433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2940bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2941bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2942bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2943bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2944bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2945bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2946bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2947bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2948bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
294946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
29501a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
29515a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
29525a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
295392551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
295492551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2955f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
2956f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
2957f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
2958f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
2959f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
2960f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
2961f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
2962f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
2963f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
2964f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
2965b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2966f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
2967181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2968181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2969181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2970181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2971181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2972181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2973181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2974181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
297582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
29761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
297782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
297882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
297982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
298082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
298182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
298282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
298382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
29842558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class DiscardConfirmDialogFragment extends DialogFragment {
29852558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
29862558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
29872558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
29882558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(R.string.confirm_discard_text)
29892558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.discard,
29902558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
29912558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                @Override
29922558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int which) {
29932558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).doDiscardWithoutConfirmation();
29942558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
29952558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
29962558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
299782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
299882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
299982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3000efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
30012558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = new DiscardConfirmDialogFragment();
30022558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "discard confirm");
3003efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
300482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
300582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
300682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
300782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
300882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
300982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
30102558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void doDiscardWithoutConfirmation() {
30117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
301282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
301382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
3014b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
301578ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
3016cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
3017cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
30180bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
3019cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
302082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
302182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
302282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
302382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
302482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
302582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
302682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
302782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
30282558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // Display a toast to let the user know
30292558b509117872e539a6eaeb72aa63425529d50bTony Mantler        Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
303082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
303182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
303282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
303382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
303482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
303582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3036eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
3037eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
3038eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
3039eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
3040eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
3041eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
3042eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3043eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3044eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
304548e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
3046eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3047eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
3048eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3049eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
3050eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
3051eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
305240882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
305340882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
305440882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
3055eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
3056eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
305775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
305840882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
305940882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
306040882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
306140882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
306240882430c874ff29890ec6fa31f7649788cbc470mindyp    }
306375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
306475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
306575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
306675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
30670bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
306875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
306975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
307075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
307175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
307275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
307375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
307475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
307575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
307675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
307775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
30780bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
307975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
308075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
308175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
308275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
308375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
308475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
308575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
308675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
308775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
308875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
308975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
309175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
309375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
309575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
309675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
309775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
309875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
310075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
310175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
310275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
310375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
310475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
310575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
310675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
310775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
310875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
310975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
311075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
311175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
311275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
311375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
311475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
311575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
311675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
311775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
311875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
311975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
312075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
312175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
312275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
312375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
312475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
312575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
312675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
312775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
312875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
312975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
313075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
313175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
313275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
313375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
313475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
313575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
313675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
313775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
313875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
313975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
314075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
314175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
314275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
314375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
314475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
314575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
314675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
314775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
314875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
314975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
315075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
315175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
315275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
315375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
315475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
315575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
315675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
315775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3158e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3159e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3160e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3161e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3162e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3163e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3164e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3165bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3166bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3167bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3168bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3169bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
317096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
317196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
317296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
317396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
3174a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3175a990a715012379451344246c5156d29938f12886Alice Yang                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
3176a990a715012379451344246c5156d29938f12886Alice Yang                        null, null);
317796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
317896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
317996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3180b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3181b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3182b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
318396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
318496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
318596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
318696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
318796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
318896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3189b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3190b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3191a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3192b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3193b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3194b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3195a990a715012379451344246c5156d29938f12886Alice Yang                    initFromRefMessage(mComposeMode);
3196a990a715012379451344246c5156d29938f12886Alice Yang                    finishSetup(mComposeMode, intent, null);
3197a990a715012379451344246c5156d29938f12886Alice Yang                    if (mComposeMode != FORWARD) {
3198b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3199b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
32000aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
32010aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3202b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3203b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3204b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3205b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3206b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3207b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3208b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
320996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3210b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3211a990a715012379451344246c5156d29938f12886Alice Yang            case REFERENCE_MESSAGE_LOADER:
3212a990a715012379451344246c5156d29938f12886Alice Yang                // Only populate mRefMessage and leave other fields untouched.
3213a990a715012379451344246c5156d29938f12886Alice Yang                if (data != null && data.moveToFirst()) {
3214a990a715012379451344246c5156d29938f12886Alice Yang                    mRefMessage = new Message(data);
3215a990a715012379451344246c5156d29938f12886Alice Yang                }
32169f855d667e34fbf0d330845225c26956e540b819Andy Huang                finishSetup(mComposeMode, getIntent(), mInnerSavedState);
3217a990a715012379451344246c5156d29938f12886Alice Yang                break;
3218b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3219b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3220b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3221b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3222faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3223faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3224b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3225b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3226dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3227b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3228b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3229b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3230b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3231b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3232b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3233b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3234b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3235faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3236faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3237faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3238b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3239b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3240b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3241b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3242b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3243b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3244b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3245b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3246b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3247b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3248b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3249b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3250b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3251b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3252b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3253b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
325496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3255b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3256b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3257b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
325896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
325996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
326096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3261b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3262b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3263b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3264b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3265b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3266b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3267b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3268b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3269b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3270b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3271b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3272b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
327396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
327496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
327596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
327696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
327783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
327883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
327983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
328083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
328183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
32821f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3283