ComposeActivity.java revision 9f855d667e34fbf0d330845225c26956e540b819
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;
25b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment;
26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction;
2796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager;
286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
2982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
3196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader;
3282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader;
3582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
388e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
3982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor;
421ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable;
4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
46ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString;
4782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
48c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
4982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
5046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
51c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity;
5362d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent;
54326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
55b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
56b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
61b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection;
6262d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo;
63326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
648e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
65433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
67013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
687b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
69c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
715680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService;
725c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
731ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView;
7440882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
759932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
765a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
7730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
7833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
815680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
833ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8592551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
86181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
8730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
883ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
8912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
901ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
92fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
93b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
95434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
96febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
97b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
9830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
9930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
10046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
10846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
109bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
11046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1141c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
115bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
11682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
11746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
11846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1195a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
120a990a715012379451344246c5156d29938f12886Alice Yang        AttachmentAddedOrDeletedListener, OnAccountChangedListener,
121a990a715012379451344246c5156d29938f12886Alice Yang        LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
122a990a715012379451344246c5156d29938f12886Alice Yang        FeedbackEnabledActivity {
1236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
12415f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int COMPOSE = -1;
12515f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY = 0;
12615f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY_ALL = 1;
12715f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int FORWARD = 2;
12815f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int EDIT_DRAFT = 3;
1296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
13196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
133326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
134326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1351623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1361d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
137a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
146d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1479a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
14862066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
14962066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
15882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
16482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
16882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
16982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1701f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
1726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1766349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
178daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
180e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
181f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1825680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    /** If set, we will clear notifications for this folder. */
1835680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder";
1845680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
1853ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
18636bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
187b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
188b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
189b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
190434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
191bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
192bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
194b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
195013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
196013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
197013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
199e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
2008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
201e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
202e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
203e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
204e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_END = null;
205e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
20696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
207b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
208a990a715012379451344246c5156d29938f12886Alice Yang    private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
20947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
210b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2112db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2122db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2149f855d667e34fbf0d330845225c26956e540b819Andy Huang    private static final String KEY_INNER_SAVED_STATE = "compose_state";
2159f855d667e34fbf0d330845225c26956e540b819Andy Huang
21682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
21782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
21882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
21982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
220c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
221c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
222c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2257b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
22633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
22792551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
228181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
22982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
233326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
23446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
23546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
23646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
237433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2381a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2392eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
240eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2411883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2421883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
243013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
244eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
24582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
24782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
24882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
24982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
250eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
251b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
252b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
25544a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
25793b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
25893b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2593ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
260326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
261daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
262daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
263daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
264cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
265cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
266cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
267b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
268a990a715012379451344246c5156d29938f12886Alice Yang    private boolean mShowQuotedText = false;
2699f855d667e34fbf0d330845225c26956e540b819Andy Huang    private Bundle mInnerSavedState;
270daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
271daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2721623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2731623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2741623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2751623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2761623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2771623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2781623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2801623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2811623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
2821623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
283daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
284326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
285326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2863ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
2871ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, EDIT_DRAFT, null, null);
288326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
289326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
29333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2941ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, null, COMPOSE, null, null);
2956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2986349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2996349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3000aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
3010aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
3020aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
3030aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3040aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3070aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3080aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3110aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3140aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3150aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3160aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3170aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3180aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3190aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3200aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3210aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3220aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3230aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3240aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3250aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3260aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3270aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3283ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
3291ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, REPLY, null, null);
3306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
3361ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, REPLY_ALL, null, null);
3376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
3431ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, FORWARD, null, null);
3446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    public static void reportRenderingFeedback(Context launcher, Account account, Message message,
3471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String body) {
3481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, FORWARD, "android-gmail-readability@google.com", body);
3491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    }
3501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
3511ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    private static void launch(Context launcher, Account account, Message message, int action,
3521ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String toAddress, String body) {
3536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
357bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
358bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
359bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
360bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
361bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
3621ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (toAddress != null) {
3631ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_TO, toAddress);
3641ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3651ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (body != null) {
3661ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_BODY, body);
3671ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
3696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
3718e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
3728e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
3738e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
3748e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
3759f855d667e34fbf0d330845225c26956e540b819Andy Huang        mInnerSavedState = (savedInstanceState != null) ?
3769f855d667e34fbf0d330845225c26956e540b819Andy Huang                savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
377b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
378b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
379b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
380b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
3819f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle savedState = mInnerSavedState;
38246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
383818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
384e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
38562066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
386a990a715012379451344246c5156d29938f12886Alice Yang        mShowQuotedText = false;
387e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
38847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
38947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
3909f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (hadSavedInstanceStateMessage(savedState)) {
3919f855d667e34fbf0d330845225c26956e540b819Andy Huang            action = savedState.getInt(EXTRA_ACTION, COMPOSE);
3929f855d667e34fbf0d330845225c26956e540b819Andy Huang            account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
3939f855d667e34fbf0d330845225c26956e540b819Andy Huang            message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
39462066e47fe69c33b60ed970e46809ba81d044064Mark Wei
3959f855d667e34fbf0d330845225c26956e540b819Andy Huang            previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
3969f855d667e34fbf0d330845225c26956e540b819Andy Huang            mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
397e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
39847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
399e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
400e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
401e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
40262066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
403e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
404b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
405e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
40662066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
40792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
40892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
409818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
410818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
411818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
412bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
4135680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
4145680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
4155680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
4165680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4175680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4185680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
419d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
42048cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
42148cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder);
4225680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4235680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4245680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4255680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
426daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
427daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
428daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
429daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
430daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
431daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
432daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
433daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
434daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
435daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
436daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
43796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
438a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = true;
439a990a715012379451344246c5156d29938f12886Alice Yang            mComposeMode = action;
440a990a715012379451344246c5156d29938f12886Alice Yang            getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
44196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
44296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
443e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
444e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
4459f855d667e34fbf0d330845225c26956e540b819Andy Huang            showCcBcc(savedState);
446a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
447e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
448e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
4498960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
4508960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
451ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
452bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
453bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
454bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
455bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
456bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
457bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
458bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
459bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
460bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
461bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
462bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
463bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
464bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
465bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
466bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
467bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
468a990a715012379451344246c5156d29938f12886Alice Yang            LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
469a990a715012379451344246c5156d29938f12886Alice Yang
470a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
471a990a715012379451344246c5156d29938f12886Alice Yang            if (message.refMessageUri != null) {
472a990a715012379451344246c5156d29938f12886Alice Yang                // If we're editing an existing draft that was in reference to an existing message,
473a990a715012379451344246c5156d29938f12886Alice Yang                // still need to load that original message since we might need to refer to the
474a990a715012379451344246c5156d29938f12886Alice Yang                // original sender and recipients if user switches "reply <-> reply-all".
475a990a715012379451344246c5156d29938f12886Alice Yang                mRefMessageUri = message.refMessageUri;
476a990a715012379451344246c5156d29938f12886Alice Yang                mComposeMode = action;
477a990a715012379451344246c5156d29938f12886Alice Yang                getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
478a990a715012379451344246c5156d29938f12886Alice Yang                return;
479a990a715012379451344246c5156d29938f12886Alice Yang            }
480e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
481e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
4820aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
483a990a715012379451344246c5156d29938f12886Alice Yang                mShowQuotedText = true;
484e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
4858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
4868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
487bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
488a990a715012379451344246c5156d29938f12886Alice Yang
489a990a715012379451344246c5156d29938f12886Alice Yang        mComposeMode = action;
4909f855d667e34fbf0d330845225c26956e540b819Andy Huang        finishSetup(action, intent, savedState);
49196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
492bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
493b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
494faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
495faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
496b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
497b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
498faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
499b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
500b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
501b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
50226d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
503b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
504faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
505dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
506b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
507b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
508b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
509b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
510b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
511b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
512b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
513b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
514b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
515b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
516faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
517b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
518b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
519b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
520b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
52147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
52247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
52347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
52447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
52547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
52647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
52747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
5287ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
5297ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
5307ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
5317ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
5327ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
5337ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
53447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
5355ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
5365ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
5375ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
53847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
53947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
5400617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
5410617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
5420617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
5430617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
5440617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
54547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
54647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
54747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
54847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
549b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
55047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
55147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
55247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
553b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
55447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
55547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
55647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
55747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
55847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
55947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
56047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
561b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
56247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
56347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
56447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
56547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
566b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
567b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
568b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
56947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
57047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
57147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
57247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
57347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
574a990a715012379451344246c5156d29938f12886Alice Yang    private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
57534a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
576bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
577eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
57846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
579818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
580f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
581f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
582f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
583f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
584f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
585a990a715012379451344246c5156d29938f12886Alice Yang        initActionBar();
586e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
587e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
588d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
589d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
590d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
591d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
592d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
593d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
594d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
59575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
596326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
597a990a715012379451344246c5156d29938f12886Alice Yang        updateHideOrShowQuotedText(mShowQuotedText);
5981623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
5999f855d667e34fbf0d330845225c26956e540b819Andy Huang        mRespondedInline = mInnerSavedState != null ?
6009f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
6011623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
6021623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
6031623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
60471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
60571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
606ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) {
607f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
608f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
609f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
61071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
61171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
61240882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
613433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
614433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
615433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
616433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
617433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
618433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
619433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
620433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
621433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
622433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
623433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
624433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
625433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
626433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
627433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
628433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
629433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
630433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
631433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
632433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
6332708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
6342708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
6352708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
6362708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
637ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                //$FALL-THROUGH$
638433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
639433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
640433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
641433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
642433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
643433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
644433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
645433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
646433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
647433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
648433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
649433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
650433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
651433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
652433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
653433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
654433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
655433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
656433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
657433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
6588743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
659433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
660433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
661433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
6621a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6631a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
6641a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
6651a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
6661a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
6671a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
6681a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
669818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
670b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount, mAccounts);
671818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
6721a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6731a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
674eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
675eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
676eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
677eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
678eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
679eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
680eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
681eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
682eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
683eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
684a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
6853d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
6863d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
687a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
688a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
689eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
690eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
691eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
692eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
693b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
694eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
695b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
696b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
697a990a715012379451344246c5156d29938f12886Alice Yang            // We were waiting for the user to create an account
698b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
699b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
700b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
701b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
702b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
703b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
704b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
705b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
706eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
707eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
708eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
709eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
710e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
7117bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        final boolean hasAccounts = mAccounts != null && mAccounts.length > 0;
7127bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7137bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            clearChangeListeners();
7147bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
715e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
7169f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (mInnerSavedState != null) {
7179f855d667e34fbf0d330845225c26956e540b819Andy Huang            if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
7189f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
7199f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
720e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
721e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
722e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
723e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
724e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
725e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
726e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
727e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
728e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7297bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7307bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            initChangeListeners();
7317bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
732e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
733e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
734e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
735eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
736eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
7379f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle inner = new Bundle();
7389f855d667e34fbf0d330845225c26956e540b819Andy Huang        saveState(inner);
7399f855d667e34fbf0d330845225c26956e540b819Andy Huang        state.putBundle(KEY_INNER_SAVED_STATE, inner);
7409f855d667e34fbf0d330845225c26956e540b819Andy Huang    }
7419f855d667e34fbf0d330845225c26956e540b819Andy Huang
7429f855d667e34fbf0d330845225c26956e540b819Andy Huang    private void saveState(Bundle state) {
743b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
744b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
745b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
746b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
747e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
748e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
749e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
750e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
751e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
752e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
753e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
754e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
755e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7566273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
7576273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
758151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
759d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
760d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
761d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
762e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
763e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
764e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
765e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
766e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
767e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
768e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
769eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
770e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
771e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
772e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
773e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
774e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
776e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
777e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
778e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
779e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
780e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
781e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
7821f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
783e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
784e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
785e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
7861f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
787e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
789e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
790e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
791e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
792326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
793326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
7941623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
795816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
79662066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
79762066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
799e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
800e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
801e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
802e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
803e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
804e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
805e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
806e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
807e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
808e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
809e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
811e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
812e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
813d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
814e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
815e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
816e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
8188960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8208960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
8218960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
823b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
824b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
825e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
826e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
827e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
828a990a715012379451344246c5156d29938f12886Alice Yang        message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
829e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
830e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
831e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
832e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
833e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
834e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
835e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
836e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
837e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
838e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
839e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
8408960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
8418960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
8421f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
8438960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8448960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8458960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
846e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
8471f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
8481f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
849ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static String formatSenders(final String string) {
8503c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
8513c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
8523c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
8533c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
8543c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
8553c9115813343861a44133b805fb9f55512d20948Mindy Pereira
856818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
857818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
858bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
859bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
860bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
86123e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
86223e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
863b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
864b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
86523e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
866fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
867f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal            MailActivity.setNfcMessage(mAccount.name);
868fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
869818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
870818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
871e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
8729a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        String accountString = null;
873e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
87462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
87562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
876b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount, mAccounts);
8779a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
8789a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
8799a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
8809a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
8819a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
8829a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
8839a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
8849a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
885e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
886e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
887e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
888e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
889e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
890e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
891e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
89262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
89362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
894238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
89562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
8969a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
89762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
8989a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
89962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
900a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
901a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
90262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
90362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
904a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
90562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
906a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
907a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
908a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
909a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
910a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
91146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
91246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
91362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
91462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
91562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
91662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
91762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
91862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
91962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
92062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
92162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
92262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
92362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
92462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
92562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
92662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
92762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
92962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
93062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
93162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
93262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
93362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
93462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
93562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
93662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
93762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
938326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
93962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
94062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
94189bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
94262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
94362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
9455ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getToAddresses()));
9465ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getCcAddresses()));
94762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
94962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
95062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
95162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
95262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
95362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
95462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
95562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
95662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
95762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
95862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
95962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
96062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
96162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
96262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
96462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
96562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
96762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
96962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
9701617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
9711617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
9721617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
9731617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
9741617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
9751617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
97662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
97762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
97862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
97962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
98062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
98162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
98262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
98362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
98462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
985ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) {
986ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final ReplyFromAccount from : account.getReplyFroms()) {
98762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
98862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
98962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
99062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
991cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
992cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
99362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
995e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
9968960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
99862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
99962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
100062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
1001cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
100262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
100362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
100462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
100562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
100662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
100762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
100862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
100962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
101062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
101162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
101262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
101346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
1014b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
1015a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
10168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
10178e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
10188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
10198e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
10207b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
102193b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
1022cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
1023cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
1024cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
102593b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
1026cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
1027cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
1028cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
1029818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
103041500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mTo.setTokenizer(new Rfc822Tokenizer());
1031818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
103241500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mCc.setTokenizer(new Rfc822Tokenizer());
1033818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
103441500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mBcc.setTokenizer(new Rfc822Tokenizer());
103582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
103682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
10376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
103862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
103946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
104046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
1041433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
10421a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
10432eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1044eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
10455a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1046326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1047326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
104862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
104962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
105062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
105162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
105262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
105362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
105462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
105562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
105662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1057e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1058e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1059e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1060e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1061e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1062e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1063e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1064e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1065e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1066e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1067cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1068cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1069cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1070cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1071cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1072cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1073cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1074cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1075cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1076cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
107775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
107875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
107975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
108075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
10811d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
10821d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
108375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
108475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1085cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1086cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1087cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1088cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1089cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1090cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1091cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1092cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1093cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1094cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1095cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1096cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
109775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1098818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
109975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
110075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1101a990a715012379451344246c5156d29938f12886Alice Yang    private void initActionBar() {
1102a990a715012379451344246c5156d29938f12886Alice Yang        LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
1103eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1104e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1105e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1106e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1107a990a715012379451344246c5156d29938f12886Alice Yang        if (mComposeMode == ComposeActivity.COMPOSE) {
1108eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1109eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1110326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1111eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1112326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1113326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1114326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1115eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1116eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1117a990a715012379451344246c5156d29938f12886Alice Yang            switch (mComposeMode) {
1118326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1119eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1120326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1121326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1122eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1123326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1124326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1125eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1126326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1127326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
11286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1129fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1130fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1131fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
11326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
11336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
11340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
11350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
11361ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
11371ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // Check if To: address and email body needs to be prefilled based on extras.
11381ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // This is used for reporting rendering feedback.
11391ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
11401ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            Intent intent = getIntent();
11411ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            if (intent.getExtras() != null) {
11421ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String toAddresses = intent.getStringExtra(EXTRA_TO);
11431ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (toAddresses != null) {
11441ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
11451ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String body = intent.getStringExtra(EXTRA_BODY);
11471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (body != null) {
11481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    setBody(body, false /* withSignature */);
11491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            }
11511ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
11521ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
115396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
115496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
115596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
115696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
115729a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
115896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
115996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
116096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
116196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
116296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
116396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
11640aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
11658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
11668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
11678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
11688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
11698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11700aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1171e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
11728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
11746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1175c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1176c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1177e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
11781f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1179bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1180bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1181bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1182bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1183bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
1184bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
1185bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
1186bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
1187bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
11882421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
11892421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
11902421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
11915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
11922421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
11932421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1194cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1195002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1196bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1197002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1198bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1199752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1200002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1201752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1202752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1203752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1204c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1205c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1206752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1207752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1208752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
12091a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1210c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1211002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1212002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1213bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1214752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1215752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1216752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1217752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1218752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1219002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1220752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1221752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1222002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1223002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1224002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1225002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
12263971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1227bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1228bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1229bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
12308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
12318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
12328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
12338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
12348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
12358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
12368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
12378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
12388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
12398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
12408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
12418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
12428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
12438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
12448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
12458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
12468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
12478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12480b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
12498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
12508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
12518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1252dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
12538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
12548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
12598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
12618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
12638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
12678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1280dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1282dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
12838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1284dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
12858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
12878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
12888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
12898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
12948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
12958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
12968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
12978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
12988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1300e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1301e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
13028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1304a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1305a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1306a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
13078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
13088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
13098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
1310a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
13117dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee            return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME);
1312a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1313a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1314a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1315a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1316a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1317a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1318a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1319a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
13208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
13237dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from
13247dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * changing '+' into ' '
13257dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     *
13267dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @param toReplace Input string
13277dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @return The string with all "+" characters replaced with "%2B"
13287dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     */
13297dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    private String replacePlus(String toReplace) {
13307dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee        return toReplace.replace("+", "%2B");
13317dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    }
13327dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee
13337dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    /**
13348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
13358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
13368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
13378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
13388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
13398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
13408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
13418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
13448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
13468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
13508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1351a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1352a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1353a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
13548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
13568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
13578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
13598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13747dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)),
13757dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                        UTF8_ENCODING_NAME));
13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
13788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
13798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
13838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13857dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME),
13868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
13878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1393bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1394bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1395434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1396434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1397434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1398434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1399434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1400434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1401434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1402434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1403434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1404434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1405434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1406434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1407434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1408434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1409434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1410434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1411434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1412434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1413434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1414434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
14153cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1416434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
14173cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14183cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
14193cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
14203cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
14213cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
14223cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
14233cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1424434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1425434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1426434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1427434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
14283cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14293cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1430434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1431434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1432434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
14333cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
14343cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
14353cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1436eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1437eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1438f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
143903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
144003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
144103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
144203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1443f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1444f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1445f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1446f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1447f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1448f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1449f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1450f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1451f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14525c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1453f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1454f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1455434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1456f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1457f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1458f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1459f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
14609a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
14619a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
14629a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
14639a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
14649a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
14659a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
14669a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
14679a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
14689a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
14699a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
14709a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
14719a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
14729a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
14739a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
14749a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
14759a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
14769a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
14779a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
14789a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
14799a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
14809a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1481f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14829a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1483f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1484f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
14859a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1486f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
14879a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1488f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1489f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1490f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1491f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1492f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1493f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1494f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1495f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1496f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1497f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1498f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1500e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
15019932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
15029932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
150346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
150446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
150546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1506ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1507326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1508326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1509ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1510326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1511ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1512326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1513ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1514ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1515cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1516ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1517ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
151846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
151946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1520a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1521326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1522326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1523326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1524326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1525326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1526326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1527326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1528326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1529326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1530013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1531013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1532013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1533013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1534013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
15352421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
15362421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
15372421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
15385c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
15395c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
15402421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
15412421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1542013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
15435c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
15445c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
15455c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1546434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1547434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1548434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1549434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
15505c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
15515c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
15525c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
15535c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
15545c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1555434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
15569932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
15579932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
15589932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1559013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
15609932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
15619932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1562434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1563013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1564013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1565013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
15660aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
15674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
15684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
15694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
15704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
1571ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        initReplyRecipients(refMessage, action);
15724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1574818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
1575ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    void initReplyRecipients(final Message refMessage, final int action) {
15765ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp        String[] sentToAddresses = refMessage.getToAddresses();
1577a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
157865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        String replytoAddress = refMessage.getReplyTo();
157965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
158065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (TextUtils.isEmpty(replytoAddress)) {
158165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            replytoAddress = refMessage.getFrom();
158265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
15834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
15854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
15864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1587a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1588a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
1589ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            toAddresses = initToRecipients(refMessage.getFrom(), replytoAddress, sentToAddresses);
1590a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1591a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
15924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
1593ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            toAddresses = initToRecipients(refMessage.getFrom(), replytoAddress, sentToAddresses);
1594154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
1595ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, sentToAddresses);
1596ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, refMessage.getCcAddresses());
15974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
15984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
16024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
16034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
16068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
16078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
16084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1610bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1611bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1612bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1613bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
16144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
16154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
16164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
16174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
16184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
16208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
16244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
16254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
16278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
16288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
16328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
16338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
16348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
16358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
16368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
16378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
16384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1641ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) {
1642ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final HashSet<String> hash = new HashSet<String>();
1643ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final Rfc822Token[] tokens : list) {
16444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
16454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
16464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
16494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
16524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
16534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
16544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
16564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
16574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
16594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
16624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
16634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
16644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
16654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1668ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static void addAddressToList(final String address, final RecipientEditTextView list) {
16694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
16704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
16714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1672ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
16734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
16754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
16764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16794a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
1680ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    protected Collection<String> initToRecipients(final String fullSenderAddress,
1681ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            final String replyToAddress, final String[] inToAddresses) {
16824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
16834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
16844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
16854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
16864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
16874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
168865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
16893ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
16904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
169165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
169265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
169365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
169465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
169565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
169665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
169765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
169865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
169965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
170065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
170165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
170265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
170365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
170465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
170565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1706fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
17071469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
17084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
17104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1712ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void addRecipients(final Set<String> recipients, final String[] addresses) {
1713ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : addresses) {
1714cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1715cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
17164a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
17175ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
17184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
17194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
172146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
172246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1723cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1724cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1725cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1726cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1727cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param accountAddress currently selected account
1728cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1729cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1730cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
17315ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
17325ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1733fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1734cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1735cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
17363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
17373ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
173846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
173946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
174046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
174146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
174246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
174346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
174446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
174546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
174646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
174746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
174846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1749c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1750c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
175146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
175246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
175346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
175446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
175546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
175646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
175746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
175846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1759818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1760818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1761818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1762818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1763eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1764eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1765818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1766679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
176782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1768679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
176933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
177033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1771c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
177233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1773c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
177482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1775c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
177682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
17778e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
17788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
17808e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
17818e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
17828e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1783a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
17848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
17858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1786a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
17878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
1788cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_photo_attachment:
1789cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_PHOTO);
1790cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
1791cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_video_attachment:
1792cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_VIDEO);
1793cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
17948e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
17958e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1796b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1797b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1798b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1799b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1800b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1801b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1802b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1803b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1804b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1805b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
18061d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
18071d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
18081d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
18091d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
18101d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
18111d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
18121d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
18131d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
18141d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
18151d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18161d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
18171d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
18181d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
18191d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18201d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
18211d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
182282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
18231d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
18249f855d667e34fbf0d330845225c26956e540b819Andy Huang        enableSave(mInnerSavedState != null ?
18259f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
18261d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
18271d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
18281d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
18291d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
18301d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
183182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
18323ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
18333ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
18343ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
18353ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
18363ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
18373ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
18383ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
18393ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
18403ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
18413ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1842b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1843b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1844b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1845b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1846ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1847ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1848818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1849ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1850ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1851ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1852ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1853ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1854ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1855ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1856ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1857ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1858ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1859ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1860ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1861ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1862ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1863ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1864b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1865b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
186675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1867b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
18682db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_photo_attachment:
18692db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_PHOTO);
18702db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                break;
18712db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_video_attachment:
18722db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_VIDEO);
18737b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1874ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1875ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1876b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
187733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
187848e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira                doSave(true);
187933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
188033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
188133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
188275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1883efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1884efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1885efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
18861f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
18871f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
18881f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1889fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1890daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                onAppUpPressed();
1891fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1892fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
189330745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook                Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
1894fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1895fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
189617beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook                Utils.sendFeedback(this, mAccount, false);
1897fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
189875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
189975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
190033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1901b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1902b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1903b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1904326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1905b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1906b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1907b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1908b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1909b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1910b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1911b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1912b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1913b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1914b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
19151672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
19161672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
19171672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
1918daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1919daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1920daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1921daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1922daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1923daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1924daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1925daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1926daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1927daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1928daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
19290c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
1930daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1931daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1932daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1933daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1934daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1935daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
193633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
1937dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
193833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
193933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
194048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
1941dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
194248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
194348e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
1944e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1945e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
194682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
19477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
19487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
194982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
195082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
195182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1952e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1953e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
195482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
195582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1956e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1957e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1958e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
195944a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
196082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
196182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
196244a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
196382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
196482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
196582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
196644a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
196782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
196882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
196982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
197082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
19717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
197282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
197392551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
19747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
19757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
197682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
197782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
197882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
197944a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
198044a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
198182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
198282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
198382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
198482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
1985febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
1986febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
1987febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
1988febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
1989cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1990cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1991eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
199282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
199382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
199482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
199582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
199682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
199782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
1998ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount);
199972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
200072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
200172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
200272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
200372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
200472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
200572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
200672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
200772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
200872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
200972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
201072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
201172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
201272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
201372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2014ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private void sendOrSaveMessage(final long messageIdToSave,
2015ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) {
201672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
201772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
201872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
201972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
202072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
202172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
202272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
20243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
20253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
20263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2027013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
20283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
202972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
2030013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
20313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
20323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
20333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
20343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
20353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
20363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
20373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
20383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
20393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
20403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
20413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
20423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
20433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
20443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
20453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
20463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
20473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
20483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
20493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
20503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
20513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
20523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
20533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
205472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
20553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
20563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
20573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
20583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
20603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2061ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) {
20623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
20633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
20643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
2065ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                for (final String key : keys) {
20663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
20673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2068ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
20693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
20703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
20713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2072ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
20737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
20747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
207582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
207672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
207782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
207872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
207972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Use the {@link ContentResolver#call()} method to send or save the message.
208072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
208172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
208272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2083ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle callAccountSendSaveMethod(final ContentResolver resolver,
2084ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final Account account, final String method,
2085ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage) {
208672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
208772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
208872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
208972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
209072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
209172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
209272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
209372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
209472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
209572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
209672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
209772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
209872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
209972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
210072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
210172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
210272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
210372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
210472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
210582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
210672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
21073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
21083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
21093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
21103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
21113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
21123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
211472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
211582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
211682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
211782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2118e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2119e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
212092551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
212182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
21223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2123e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2124e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
21263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
212782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
21293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
213182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
213382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
213482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
21353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
213782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
213882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
213982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
214082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
214182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
21423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
21443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
21453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
21463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
21483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
21493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
21503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
21513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
2152ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle initializeAttachmentFds(final Context context,
2153ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final List<Attachment> attachments) {
21543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
21553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
21563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
21593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
21603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
21623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
21633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
21643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
21673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
21683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
21693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
21703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
21713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2172c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2173c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2174c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2175c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2176c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2177c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2178c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2179c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2180c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2181c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2182c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2183c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2184c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
21853c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
21883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
21893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
21933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
219782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
219882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
219982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
220182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
220282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
220782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
221382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
221982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
222082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
222182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
222382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
222782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
222982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
223082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
223182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
223282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
223382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2235ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) {
2236e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2237e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2238e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
2239ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : to) {
224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
224182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
224282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
224382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
224482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
224582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
224682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
224782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
224882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
225482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
225582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
225682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
225782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
225882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
225982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
226082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
22610bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                            @Override
226282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
226382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
226482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
226582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
226682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
226782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
226982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
227082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
227182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
227282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
227382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
227482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
227582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
227682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
227782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
227882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2279eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
228082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
228182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
228282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
228382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
228482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
228582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
228682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
228782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
228882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
22897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
229082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
229182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
229282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
229382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2294a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2295d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2296a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
229882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
229982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2301bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
230282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
230382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
230482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
230582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2306bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2307bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2308bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2309bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2310bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2311bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2312bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2313bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2314bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2315bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2316bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2317bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2318bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2319bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2320bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2321bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2322bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2323bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2324bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2325bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2326bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2327bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2328bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2329bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2330bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2331bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2332bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2333bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2334bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2335bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
233682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
233782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
233882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
233982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
234082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
234182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
234282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
234382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2344eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
234582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
234633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
234733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
234882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2349181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
2350181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2351181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2352181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2353181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2354181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2355dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2356009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2357009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2358dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2359dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2360dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2361009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2362009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2363009b3712ff1657fa839049826451321fdd938d32Mark Wei
2364ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final String[] to, cc, bcc;
2365ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Editable body = mBodyView.getEditableText();
2366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2379181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2381181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23970bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
2398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
2399ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                sendOrSave(mBodyView.getEditableText(), save, showToast);
2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
2407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
2408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
2418181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
2419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
2423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
2424181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2425181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2426181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2427181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2428181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
2429181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
2430181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2431181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2432181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2433181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2434ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        sendOrSave(body, save, showToast);
2435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2436181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2439181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2440181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
24415c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2443181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2446181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2450181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2451181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
2458181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
2459181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
2460181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
2461181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2462181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
2463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
2464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
2465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
24666edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .setNegativeButton(R.string.cancel, this)
24676edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .show();
2468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2474181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2475181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2476181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2477181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2478181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2479181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2480181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2481181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2482181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2483181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2491e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
249205b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
249344a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
249444a6339dd80f4b5b9e5d54567021698d92467c5emindyp            ReplyFromAccount draftAccount) {
2495b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
249629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2497b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2498c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2500e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2501e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
250229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
25038960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
250492551d057965689f1952faeb06763f0762bc717fMindy Pereira
2505e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2506b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2507b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
250805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
250929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
251029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
251129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2512e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2513e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2514e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2515e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
251655271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
251755271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
251855271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
251912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2520e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
252129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2522e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2523e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2524e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2525e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
252629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
252729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2528002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
252912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2530c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2531c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2532c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2533c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2534c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2535c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2536c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2537c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2538c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2539c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2540c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2541c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2542c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2543e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
254412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
254512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
254612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
25473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
25483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
254944a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
255044a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
255182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
255682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
255982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2560b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2561b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2562b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2563b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2564b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2565b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2566b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2567b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2568b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2569b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2570002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2571002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2572002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2573002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2574002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2575002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2576002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2577002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2578002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2579002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2580002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2581002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2582002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2583002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2584002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2585002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2586002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2587002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2588002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
2589ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void sendOrSave(final Spanned body, final boolean save, final boolean showToast) {
2590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
25923ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
259582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
25971f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
259882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
259982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26000bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
260182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2603181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2604181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2608181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2610181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2612181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2615181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
261682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26170bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
26197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2620181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
262144a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2622181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2623181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
26247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
26257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
26267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2629181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2630181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
26317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2633181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
263482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26350bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
26377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
26387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
26397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
264182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26420bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
264447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
264547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
264647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
264747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
26487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
26497ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
26507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
26517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
26527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
26537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
26547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
26557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
26567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
26577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
265882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
26607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
26617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
26627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
26637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
26647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
266582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
26677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
26687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
26697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
26717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
26727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2674181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2675181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2676181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
267792551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
2678181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
2679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
2680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
2681181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
268292551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
2683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
2684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2693e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
269405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
269505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
269644a6339dd80f4b5b9e5d54567021698d92467c5emindyp                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount);
2697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
2699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
2700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2701b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
2702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2714181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2715181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2716181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2717181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2718181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2723181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
273082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27312db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2732013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2733013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2734d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
27352db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2736013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2737181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2739013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2740013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2741ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2742a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2743ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2744cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2745ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2746ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2747ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2748326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2749326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2750a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2751326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2752326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2753326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2754326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2755326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2756326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2757326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2758cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2759a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2760154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
276168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
27620aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
27638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2764ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2765ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2766ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2767ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2768ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
27698960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2770ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2771ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
27728960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
27738960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
277468c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
277568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
27769b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
277768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2778ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2779ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2780a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2781ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2782cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2783326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2784326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2785326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2786b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2787b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2788154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2789154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2790154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2791154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2792154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2793154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2794154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2795154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2796154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2797154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2798154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2799154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2800154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2801154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2802154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2803154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2804154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2805154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2806154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2807154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2808154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2809154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2810326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2811326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2812326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2813326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2814326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2815326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2816326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2817326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2818326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2819326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2820326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2821326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2822326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2823326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2824326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2825326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2826326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2827326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2828326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2829326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2830326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2831326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2832326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2833326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2834326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
283546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
283646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
283746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
283846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
283940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
28401623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
284109dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
28428654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
284309dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
284446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
284546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
284646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
284746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
284846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
284946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
285046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
285146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
285246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
285346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2854eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
285546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
285646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
285746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
285846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
285946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
286046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
286146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
286246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
286346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2864bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
286546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
286646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
286746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
286846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2869eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2870bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2871bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2872bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2873bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2874bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2875bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2876b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2877433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
28782708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
28792708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
2880b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
28812708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
2882b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2883b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2884b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2885b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2886b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2887433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2888433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2889433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2890bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2891bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2892bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2893bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2894bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2895bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2896bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2897bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2898bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
289946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
29001a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
29015a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
29025a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
290392551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
290492551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2905f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
2906f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
2907f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
2908f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
2909f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
2910f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
2911f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
2912f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
2913f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
2914f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
2915b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2916f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
2917181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2918181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2919181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2920181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2921181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2922181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2923181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2924181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
292582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
29261a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
292782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
292882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
292982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
293082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
293182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
293282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
293382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
293482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
293582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
293682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
293782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
293882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
293982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
294082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
294182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
294282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
294382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
294482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
294582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
294682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
294782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
294882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
294982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
295082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
295182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
295282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
295382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
295482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
295582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
295682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
295782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
295882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
295982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2960efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2961efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2962efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2963efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2964efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2965efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
296682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
296782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
296882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
296982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
297082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
297182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
297282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
297382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
29747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
297582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
297682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2977b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
297878ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
2979cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2980cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
29810bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
2982cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
298382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
298482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
298582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
298682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
298782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
298882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
298982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
299082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
299182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
299282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
299382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
299482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
299582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
299682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
299782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
299882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
299982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
300082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3001eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
3002eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
3003eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
3004eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
3005eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
3006eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
3007eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3008eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3009eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
301048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
3011eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3012eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
3013eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3014eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
3015eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
3016eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
301740882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
301840882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
301940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
3020eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
3021eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
302275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
302340882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
302440882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
302540882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
302640882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
302740882430c874ff29890ec6fa31f7649788cbc470mindyp    }
302875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
302975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
303075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
303175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
30320bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
303375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
303475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
303575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
303675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
303775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
303875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
303975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
304075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
304175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
304275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
30430bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
304475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
304575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
304675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
304775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
304875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
304975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
305075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
305175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
305275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
305375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
305475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
305575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
305675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
305775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
305875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
305975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
306075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
306175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
306275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
306375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
306475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
306575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
306675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
306775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
306875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
306975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
307075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
307175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
307275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
307375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
307475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
307575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
307675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
307775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
307875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
307975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
308075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
308175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
308275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
308375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
308475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
308575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
308675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
308775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
308875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
308975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
309075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
309175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
309275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
309375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
309475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
309575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
309675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
309875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
309975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
310075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
310175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
310275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
310375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
310475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
310575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
310675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
310775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
310875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
310975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
311075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
311175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
311275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
311375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
311475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
311575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
311675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
311775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
311875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
311975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
312075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
312175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
312275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3123e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3124e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3125e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3126e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3127e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3128e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3129e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3130bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3131bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3132bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3133bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3134bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
313596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
313696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
313796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
313896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
3139a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3140a990a715012379451344246c5156d29938f12886Alice Yang                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
3141a990a715012379451344246c5156d29938f12886Alice Yang                        null, null);
314296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
314396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
314496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3145b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3146b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3147b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
314896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
314996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
315096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
315196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
315296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
315396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3154b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3155b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3156a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3157b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3158b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3159b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3160a990a715012379451344246c5156d29938f12886Alice Yang                    initFromRefMessage(mComposeMode);
3161a990a715012379451344246c5156d29938f12886Alice Yang                    finishSetup(mComposeMode, intent, null);
3162a990a715012379451344246c5156d29938f12886Alice Yang                    if (mComposeMode != FORWARD) {
3163b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3164b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
31650aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
31660aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3167b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3168b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3169b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3170b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3171b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3172b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3173b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
317496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3175b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3176a990a715012379451344246c5156d29938f12886Alice Yang            case REFERENCE_MESSAGE_LOADER:
3177a990a715012379451344246c5156d29938f12886Alice Yang                // Only populate mRefMessage and leave other fields untouched.
3178a990a715012379451344246c5156d29938f12886Alice Yang                if (data != null && data.moveToFirst()) {
3179a990a715012379451344246c5156d29938f12886Alice Yang                    mRefMessage = new Message(data);
3180a990a715012379451344246c5156d29938f12886Alice Yang                }
31819f855d667e34fbf0d330845225c26956e540b819Andy Huang                finishSetup(mComposeMode, getIntent(), mInnerSavedState);
3182a990a715012379451344246c5156d29938f12886Alice Yang                break;
3183b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3184b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3185b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3186b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3187faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3188faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3189b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3190b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3191dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3192b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3193b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3194b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3195b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3196b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3197b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3198b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3199b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3200faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3201faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3202faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3203b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3204b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3205b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3206b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3207b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3208b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3209b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3210b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3211b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3212b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3213b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3214b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3215b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3216b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3217b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3218b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
321996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3220b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3221b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3222b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
322396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
322496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
322596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3226b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3227b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3228b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3229b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3230b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3231b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3232b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3233b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3234b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3235b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3236b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3237b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
323896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
323996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
324096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
324196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
324283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
324383e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
324483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
324583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
324683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
32471f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3248