ComposeActivity.java revision 013a23c75cf8a71c51ad1580aa84f2a8e06b6761
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;
41f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable;
423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor;
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;
7340882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
749932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
755a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
7630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
7733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
805680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8492551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
85181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
8630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
873ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
8812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
8983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
90fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
91b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9262066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
94434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
95febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
96b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
9730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
9830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
9946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1028e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
10746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
108bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
10946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1131c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
114bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
11582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
11646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
11746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1185a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
11940882430c874ff29890ec6fa31f7649788cbc470mindyp        AttachmentAddedOrDeletedListener, OnAccountChangedListener, LoaderManager.LoaderCallbacks<Cursor>,
12083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        TextView.OnEditorActionListener, FeedbackEnabledActivity {
1216349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
12215f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int COMPOSE = -1;
12315f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY = 0;
12415f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY_ALL = 1;
12515f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int FORWARD = 2;
12615f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int EDIT_DRAFT = 3;
1276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
12996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
131326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
132326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1331623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1341d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
135a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
144d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1459a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
14662066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
14762066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
15682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
15782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
15882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
16682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1681f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
16982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
17082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Key used to store the above map
17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids";
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;
20847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
209b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2102db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2112db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
21382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
21482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
21582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
21682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
217c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
218c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
219c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2208e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2227b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
22333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
22492551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
225181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
22682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
229326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
230326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
23146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
23246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
23346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
234433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2351a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2362eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
237eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2381883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2391883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
240013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
241eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
24282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
24382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
24482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
24582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
247eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
248b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
249b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
25244a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
25493b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
25593b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2563ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
257326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
258daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
259daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
260daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
261cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
262cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
263cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
264b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
265b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private Bundle mSavedInstanceState;
266daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
267daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2681623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2691623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2701623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2711623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2721623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2731623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2741623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2751623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2761623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2771623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
2781623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
279daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
280326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
281326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
283bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        launch(launcher, account, message, EDIT_DRAFT);
284326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
285326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2876349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
28933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launch(launcher, account, null, COMPOSE);
2916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2960aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
2970aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
2980aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
2990aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3000aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3010aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3020aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3030aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3040aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3070aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3080aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3110aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3140aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3150aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3160aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3170aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3180aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3190aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3200aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3210aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3220aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3230aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3243ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
3253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY);
3266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3313ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
3323ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY_ALL);
3336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3383ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
3393ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, FORWARD);
3406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static void launch(Context launcher, Account account, Message message, int action) {
3436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
347bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
348bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
349bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
350bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
351bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
3526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
3536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
3558e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
3568e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
3578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
3588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
359b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mSavedInstanceState = savedInstanceState;
360b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
361b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
362b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
363b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
364b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        Bundle savedInstanceState = mSavedInstanceState;
36546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
366818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
367e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
36862066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
36971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        boolean showQuotedText = false;
370e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
37147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
37247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
373f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (hadSavedInstanceStateMessage(savedInstanceState)) {
374e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
375e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
376e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
37762066e47fe69c33b60ed970e46809ba81d044064Mark Wei
37862066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = savedInstanceState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
379e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
380e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
38147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
382e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
383e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
384e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
38562066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
386e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
387b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
388e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
38962066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
39092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
39192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
392818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
393818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
394818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
395bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
3965680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
3975680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
3985680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
3995680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4005680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4015680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
402d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
403d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.putExtra(MailIntentService.ACCOUNT_EXTRA, account);
4045680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            clearNotifIntent.putExtra(MailIntentService.FOLDER_EXTRA, notificationFolder);
4055680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4065680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4075680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4085680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
409daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
410daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
411daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
412daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
413daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
414daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
415daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
416daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
417daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
418daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
419daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
42096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
42196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // We have a referenced message that we must look up.
42296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
42396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
42496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
425e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
426e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
427a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira            showCcBcc(savedInstanceState);
42871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira            showQuotedText = message.appendRefMessageContent;
429e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
430e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
4318960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
4328960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
433ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
434bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
435bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
436bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
437bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
438bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
439bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
440bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
441bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
442bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
443bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
444bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
445bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
446bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
447bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
448bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
449bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
450e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
45171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira            showQuotedText = message.appendRefMessageContent;
452e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
453e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
4540aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
45571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira                showQuotedText = true;
456e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
4578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
4588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
459bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
46096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        finishSetup(action, intent, savedInstanceState, showQuotedText);
46196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
462bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
463b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
464faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
465faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
466b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
467b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
468faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
469b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
470b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
471b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
47226d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
473b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
474faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
475dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
476b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
477b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
478b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
479b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
480b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
481b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
482b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
483b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
484b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
485b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
486faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
487b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
488b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
489b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
490b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
49147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
49247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
49347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
49447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
49547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
49647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
49747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
4987ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
4997ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
5007ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
5017ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
5027ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
5037ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
50447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
5055ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
5065ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
5075ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
50847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
50947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
5100617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
5110617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
5120617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
5130617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
5140617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
51547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
51647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
51747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
51847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
519b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
52047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
52147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
52247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
523b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
52447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
52547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
52647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
52747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
52847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
52947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
53047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
531b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
53247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
53347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
53447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
53547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
536b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
537b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
538b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
53947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
54047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
54147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
54247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
54347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
54496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private void finishSetup(int action, Intent intent, Bundle savedInstanceState,
54596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            boolean showQuotedText) {
54634a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
547bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
548eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
54946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
550818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
551f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
552f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
553f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
554f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
555f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
5561a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        initActionBar(action);
557e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
558e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
559d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
560d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
561d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
562d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
563d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
564d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
565d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
56675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
567326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
56871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        updateHideOrShowQuotedText(showQuotedText);
5691623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
5701623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = mSavedInstanceState != null ?
5711623f9bfde8ced840a52820da28a0939bcaa32f9mindyp                mSavedInstanceState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
5721623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
5731623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
5741623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
57571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
57671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
577f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    private boolean hadSavedInstanceStateMessage(Bundle savedInstanceState) {
578f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
579f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
580f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
58171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
58271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
58340882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
584433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
585433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
586433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
587433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
588433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
589433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
590433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
591433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
592433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
593433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
594433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
595433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
596433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
597433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
598433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
599433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
600433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
601433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
602433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
603433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
6042708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
6052708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
6062708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
6072708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
608433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
609433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
610433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
611433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
612433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
613433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
614433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
615433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
616433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
617433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
618433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
619433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
620433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
621433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
622433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
623433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
624433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
625433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
626433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
627433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
6288743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
629433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
630433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
631433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
6321a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6331a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
6341a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
6351a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
6361a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
6371a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
6381a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
639818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
640b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount, mAccounts);
641818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
6421a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
644eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
645eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
646eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
647eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
648eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
649eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
650eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
651eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
652eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
653eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
654a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
6553d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
6563d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
657a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
658a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
659eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
660eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
661eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
662eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
663b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
664eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
665b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
666b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
667b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // We were waiting for the user to create an account
668b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
669b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
670b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
671b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
672b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
673b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
674b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
675b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
676eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
677eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
678eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
679eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
680e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
68147db6d764dd4b74ddfd7fda6412e32d84d86fc9amindyp        clearChangeListeners();
682e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
683e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (savedInstanceState != null) {
684e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
685e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
686e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
687e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
688e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
689e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
690e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
691e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
692e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
693e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
694e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
695e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
6961d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        initChangeListeners();
697e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
698e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
699e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
700eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
701eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
702b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
703b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
704b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
705b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
706e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
707e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
708e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
709e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
710e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
711e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
712e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
713e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
714e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7156273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
7166273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
717151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
718d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
719d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
720d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
721e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
722e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
723e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
724e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
725e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
726e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
727e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
728eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
729e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
730e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
731e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
732e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
733e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
734e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
735e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
736e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
737e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
738e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
739e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
740e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
7411f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
742e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
743e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
744e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
7451f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
746e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
747e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
748e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
749e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
750e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
751326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
752326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
7531623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
754816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
75562066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
75662066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
757e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
758e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
760e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
761e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
762e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
763e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
764e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
765e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
766e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
767e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
768e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
769e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
770e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
771e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
772d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
773e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
774e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
776e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
7778960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
7788960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
7798960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
7808960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
781e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
782b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
783b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
784e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
785e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
786e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
787e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null;
788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
789e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
790e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
791e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
792e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
793e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
794e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
795e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
7998960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
8008960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
8011f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
8028960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8038960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8048960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
805e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
8061f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
8071f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
8083c9115813343861a44133b805fb9f55512d20948Mindy Pereira    private String formatSenders(String string) {
8093c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
8103c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
8113c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
8123c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
8133c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
8143c9115813343861a44133b805fb9f55512d20948Mindy Pereira
815818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
816818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
817bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
818bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
819bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
82023e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
82123e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
822b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
823b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
82423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
825fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
826f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal            MailActivity.setNfcMessage(mAccount.name);
827fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
828818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
829818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
830e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
8319a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        String accountString = null;
832e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
83362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
83462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
835b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount, mAccounts);
8369a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
8379a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
8389a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
8399a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
8409a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
8419a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
8429a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
8439a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
848e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
849e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
850e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
85162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
85262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
853238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
85462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
8559a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
85662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
8579a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
85862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
859a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
860a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
86162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
86262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
863a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
86462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
865a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
866a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
867a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
868a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
869a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
87046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
87146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
87262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
87362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
87462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
87562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
87662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
87762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
87862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
87962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
88062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
88162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
88262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
88362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
88462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
88562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
88662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
88762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
88862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
88962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
89062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
89162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
89262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
89362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
89462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
89562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
89662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
897326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
89862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
89962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
90089bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
90162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
90262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
90362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
9045ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getToAddresses()));
9055ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getCcAddresses()));
90662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
90762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
90862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
90962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
91062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
91162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
91262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
91362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
91462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
91562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
91662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
91762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
91862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
91962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
92062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
92162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
92262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
92362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
92462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
92562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
92662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
92762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
9291617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
9301617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
9311617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
9321617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
9331617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
9341617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
93562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
93662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
93762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
93862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
93962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
94062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
94162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
94262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
94362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getDefaultReplyFromAccount(Account account) {
945238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang        for (ReplyFromAccount from : account.getReplyFroms()) {
94662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
94762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
94962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
950cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
951cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
95262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
95362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
954e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
9558960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
95662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
95762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
95862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
95962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
960cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
96162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
96262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
96462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
96562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
96762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
96962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
97062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
97162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
97246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
973b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
974a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
9758e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
9768e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
9778e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
9788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
9797b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
98093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
981cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
982cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
983cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
98493b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
985cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
986cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
987cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
988818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
989818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
990818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
99182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
99282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
9936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
99462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
99546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
99646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
997433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
9981a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
9992eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1000eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
10015a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1002326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1003326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
100462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
100562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
100662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
100762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
100862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
100962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
101062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
101162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
101262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1013e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1014e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1015e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1016e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1017e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1018e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1019e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1020e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1021e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1022e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1023cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1024cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1025cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1026cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1027cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1028cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1029cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1030cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1031cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1032cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
103375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
103475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
103575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
103675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
10371d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
10381d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
103975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
104075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1041cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1042cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1043cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1044cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1045cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1046cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1047cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1048cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1049cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1050cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1051cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1052cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
105375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1054818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
105575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
105675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1057326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void initActionBar(int action) {
1058326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mComposeMode = action;
1059eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1060e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1061e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1062e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1063326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
1064eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1065eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1066326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1067eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1068326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1069326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1070326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1071eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1072eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1073326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            switch (action) {
1074326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1075eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1076326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1077326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1078eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1079326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1081eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1082326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1083326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
10846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1085fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1086fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1087fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
10886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
10896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
10900aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
10910aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
109296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
109396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
109496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
109596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
109629a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
109796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
109896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
109996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
110096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
110196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
110296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
11030aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
11048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
11058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
11068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
11078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
11088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1110e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
11118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
11128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
11136349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1114c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1115c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1116e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
11171f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1118bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1119bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1120bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1121bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1122bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
1123bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
1124bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
1125bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
1126bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
11272421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
11282421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
11292421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
11305c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
11312421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
11322421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1133cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1134002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1135bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1136002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1137bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1138752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1139002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1140752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1141752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1142752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1143c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1144c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1145752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1146752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1147752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
11481a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1149c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1150002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1151002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1152bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1153752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1154752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1155752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1156752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1157752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1158002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1159752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1160752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1161002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1162002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1163002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1164002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
11653971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1166bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1167bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1168bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
11698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
11708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
11718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
11728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
11748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
11758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
11768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
11778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
11788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
11798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
11808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
11818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
11828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
11838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
11848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
11858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
11868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
11870b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
11888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
11898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
11908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1191dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
11928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
11938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
11948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
11958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
11988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
11998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
12008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
12028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
12048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
12068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
12088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
12118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
12128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
12138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
12168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
12178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
12188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1219dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
12208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1221dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
12228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1223dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
12248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
12258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
12268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
12278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
12288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
12338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
12348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
12358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
12368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
12378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1239e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1240e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
12418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
12428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1243a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1244a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1245a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
12468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
12478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
12488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
12498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String replacePlus = s.replace("+", "%2B");
1250a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
1251a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME);
1252a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1253a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1254a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1255a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1256a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1257a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1258a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1259a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
12608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
12618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
12638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
12678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1280a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1281a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1282a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
12838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
12848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
12858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
12888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
12928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
12938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
12958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
12968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
12988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
12998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
13018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
13028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME));
13048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
13068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
13078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
13118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
13128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME),
13148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
13158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
13178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1321bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1322bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1323434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1324434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1325434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1326434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1327434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1328434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1329434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1330434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1331434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1332434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1333434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1334434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1335434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1336434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1337434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1338434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1339434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1340434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1341434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1342434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
13433cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1344434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
13453cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
13463cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
13473cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
13483cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
13493cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
13503cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
13513cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1352434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1353434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1354434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1355434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
13563cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
13573cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1358434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1359434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1360434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
13613cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
13623cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
13633cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1364eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1365eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1366f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
136703ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
136803ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
136903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
137003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1371f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1372f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1373f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1374f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1375f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1376f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1377f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1378f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1379f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
13805c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1381f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1382f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1383434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1384f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1385f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1386f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1387f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
13889a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
13899a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
13909a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
13919a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
13929a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
13939a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
13949a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
13959a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
13969a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
13979a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
13989a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
13999a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
14009a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
14019a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
14029a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
14039a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
14049a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
14059a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
14069a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
14079a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
14089a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1409f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14109a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1411f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1412f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
14139a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1414f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
14159a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1416f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1417f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1418f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1419f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1420f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1421f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1422f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1423f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1424f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1425f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1426f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1427e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1428e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
14299932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
14309932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
143146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
143246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
143346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1434ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1435326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1436326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1437ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1438326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1439ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1440326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1441ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1442ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1443cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1444ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1445ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
144646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
144746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1448a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1449326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1450326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1451326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1452326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1453326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1454326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1455326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1456326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1457326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1458013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1459013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1460013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1461013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1462013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
14632421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
14642421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
14652421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
14665c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
14675c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
14682421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
14692421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1470013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
14715c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
14725c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
14735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1474434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1475434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1476434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1477434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
14785c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
14795c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
14805c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
14815c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
14825c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1483434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
14849932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
14859932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
14869932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1487013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
14889932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
14899932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1490434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1491013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1492013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1493013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
14940aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
14954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
14964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
14974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
14984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
149933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira        initReplyRecipients(mAccount.name, refMessage, action);
15004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1502818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
15033ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initReplyRecipients(String account, Message refMessage, int action) {
15044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // This is the email address of the current user, i.e. the one composing
15054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the reply.
15064a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira        final String accountEmail = Address.getEmailAddress(account).getAddress();
15075ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp        String[] sentToAddresses = refMessage.getToAddresses();
1508a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
150965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        String replytoAddress = refMessage.getReplyTo();
151065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
151165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (TextUtils.isEmpty(replytoAddress)) {
151265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            replytoAddress = refMessage.getFrom();
151365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
15144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
15164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
15174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1518a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1519a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
15205ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            toAddresses = initToRecipients(accountEmail, refMessage.getFrom(),
15218960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                    replytoAddress, sentToAddresses);
1522a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1523a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
15244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
15255ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            toAddresses = initToRecipients(accountEmail, refMessage.getFrom(),
15268960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                    replytoAddress, sentToAddresses);
1527154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
15284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addRecipients(accountEmail, ccAddresses, sentToAddresses);
15295ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            addRecipients(accountEmail, ccAddresses, refMessage.getCcAddresses());
15304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
15314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
15354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
15364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
15398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
15408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
15414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1543bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1544bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1545bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1546bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
15474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
15484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
15494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
15504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
15514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
15538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
15548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
15558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
15564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
15574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
15584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
15598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
15608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
15618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
15628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
15638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
15648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
15658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
15668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
15678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
15688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
15698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
15708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
15714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) {
15754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        HashSet<String> hash = new HashSet<String>();
15764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (Rfc822Token[] tokens : list) {
15774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
15784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
15794a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
15804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
15824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
15854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
15864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
15874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
15894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
15904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
15924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
15954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
15964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
15974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
15984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addAddressToList(String address, RecipientEditTextView list) {
16024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
16034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
16044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
16064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
16084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
16094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
161365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp    protected Collection<String> initToRecipients(String accountEmail, String fullSenderAddress,
161465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            String replyToAddress, String[] inToAddresses) {
16154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
16164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
16174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
16184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
16194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
16204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
162165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
16223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
16234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
162465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
162565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
162665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
162765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
162865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
162965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
163065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
163165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
163265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
163365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
163465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
163565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
163665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
163765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
163865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1639fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
16401469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
16414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
16434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1645cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    private void addRecipients(String accountAddress, Set<String> recipients, String[] addresses) {
16464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String email : addresses) {
1647cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1648cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
16494a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
16505ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
16514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
16524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
165446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
165546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1656cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1657cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1658cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1659cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1660cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param accountAddress currently selected account
1661cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1662cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1663cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
16645ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
16655ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1666fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1667cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1668cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
16693ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
16703ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
167146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
167246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
167346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
167446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
167546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
167646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
167746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
167846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
167946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
168046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
168146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1682c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1683c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
168446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
168546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
168646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
168746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
168846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
168946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
169046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
169146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1692818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1693818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1694818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1695818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1696eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1697eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1698818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1699679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
1700c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
170182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1702679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
170333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
170433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1705c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
170633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1707c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
170882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1709c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
171082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
17118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
17128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
17148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
17158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
17168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1717a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
17188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
17198e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1720a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
17218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
1722cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_photo_attachment:
1723cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_PHOTO);
1724cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
1725cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_video_attachment:
1726cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_VIDEO);
1727cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
17288e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
17298e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1730b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1731b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1732b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1733b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1734b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1735b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1736b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1737b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1738b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1739b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
17401d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
17411d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
17421d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
17431d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
17441d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
17451d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
17461d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
17471d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
17481d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
17491d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
17501d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
17511d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
17521d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
17531d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
17541d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
17551d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
175682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
17571d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
17581d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        enableSave(mSavedInstanceState != null ?
17591d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                mSavedInstanceState.getBoolean(EXTRA_SAVE_ENABLED)
17601d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
17611d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
17621d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
17631d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
17641d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
176582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
17663ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
17673ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
17683ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
17693ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
17703ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
17713ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
17723ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
17733ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
17743ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
17753ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1776b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1777b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1778b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1779b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1780ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1781ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1782818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1783ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1784ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1785ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1786ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1787ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1788ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1789ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1790ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1791ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1792ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1793ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1794ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1795ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1796ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1797ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1798b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1799b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
180075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1801b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
18022db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_photo_attachment:
18032db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_PHOTO);
18042db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                break;
18052db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_video_attachment:
18062db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_VIDEO);
18077b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1808ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1809ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1810b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
181133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
181248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira                doSave(true);
181333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
181433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
181533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
181675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1817efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1818efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1819efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
18201f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
18211f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
18221f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1823fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1824daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                onAppUpPressed();
1825fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1826fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
182730745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook                Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
1828fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1829fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
183017beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook                Utils.sendFeedback(this, mAccount, false);
1831fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
183275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
183375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
183433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1835b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1836b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1837b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1838326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1839b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1840b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1841b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1842b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1843b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1844b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1845b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1846b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1847b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1848b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
18491672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
18501672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
18511672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
1852daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1853daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1854daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1855daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1856daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1857daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1858daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1859daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1860daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1861daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1862daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
18630c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
1864daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1865daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1866daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1867daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1868daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1869daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
187033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
1871dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
187233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
187333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
187448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
1875dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
187648e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
187748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
1878e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1879e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
188082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
18817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
18827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
188382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
188582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1886e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1887e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
188882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
188982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1890e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1891e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1892e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
189344a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
189482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
189582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
189644a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
189782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
189882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
189982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
190044a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
190182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
190282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
190382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
190482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
19057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
190682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
190792551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
19087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
19097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
191082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
191182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
191282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
191344a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
191444a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
191582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
191682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
191782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
191882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
1919febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
1920febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
1921febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
1922febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
1923cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1924cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1925eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
192682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
192782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
192882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
192982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
193082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
193182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
193272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount, message);
193372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
193472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
193572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
193672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
193772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
193872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
193972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
194072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
194172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
194272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
194372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
194472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
194572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
194672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
194772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
194872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        private void sendOrSaveMessage(long messageIdToSave, SendOrSaveMessage sendOrSaveMessage,
194972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                ReplyFromAccount selectedAccount, Message message) {
195072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
195172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
195272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
195372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
195472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
195572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
195672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
19573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
19583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
19593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
19603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
1961013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
19623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
196372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
1964013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
19653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
19663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
19673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
19683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
19693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
19703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
19713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
19723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
19733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
19743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
19753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
19763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
19773c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
19783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
19793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
19803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
19813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
19823c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
19833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
19843c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
19853c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
19863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
19873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
198872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
19893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
19903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
19913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
19923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
19933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
19943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
19953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private void closeOpenedAttachmentFds(SendOrSaveMessage sendOrSaveMessage) {
19963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
19973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
19983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
19993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                for (String key : keys) {
20003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
20013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2002ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
20033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
20043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
20053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2006ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
20077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
20087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
200982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
201072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
201182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
201272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
201372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Use the {@link ContentResolver#call()} method to send or save the message.
201472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
201572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
201672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
201772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        private Bundle callAccountSendSaveMethod(ContentResolver resolver, Account account,
201872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                String method, SendOrSaveMessage sendOrSaveMessage) {
201972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
202072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
202172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
202272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
202372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
202472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
202572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
202672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
202772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
202872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
202972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
203072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
203172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
203272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
203372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
203472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
203572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
203672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
203772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
203882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
203972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
20413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
20423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
20433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
20443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
20453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
204772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
204882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
204982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
205082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2051e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2052e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
205392551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
205482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
20553ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2056e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2057e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
205882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
20593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
206082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
20613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
20623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
206382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
206482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
206582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
206682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
206782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
20683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
207082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
207182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
207282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
207382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
207482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
20753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
20773c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
20783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
20793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
20813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
20823c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
20833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
20843c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
20853c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private Bundle initializeAttachmentFds(Context context, List<Attachment> attachments) {
20863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
20873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
20883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
20913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
20923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
20943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
20953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
20963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
20973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
20993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
21003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
21013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
21023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
21033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2104c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2105c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2106c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2107c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2108c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2109c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2110c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2111c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2112c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2113c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2114c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2115c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2116c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
21173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
21203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
21213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
21253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
212682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
212782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
212882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
212982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
213182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
213382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
213482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
213582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
213682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
213782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
213882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
213982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
214082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
214182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
214282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
214382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
214482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
214582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
214682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
214782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
214882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
214982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
215082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
215182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
215282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
215382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
215482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
215582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
215682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
215782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
215882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
215982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
216082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
216182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
216282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
216382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
216482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
216582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
216682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
216782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) {
2168e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2169e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2170e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
217182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (String email : to) {
217282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
217382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
217482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
217582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
217682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
217782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
217882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
217982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
218082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
218182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
218282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
218382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
218482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
218582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
218682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
218782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
218882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
218982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
219082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
219182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
219282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
21930bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                            @Override
219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
219782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
219882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
219982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
220182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
220282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
220782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2211eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
221382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
221982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
222082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
22217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
222382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2226a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2227d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2228a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
222982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
223082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
223182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
223282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2233bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
223582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
223682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
223782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2238bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2239bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2240bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2241bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2242bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2243bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2244bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2245bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2246bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2247bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2248bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2249bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2250bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2251bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2252bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2253bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2254bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2255bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2256bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2257bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2258bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2259bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2260bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2261bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2262bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2263bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2264bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2265bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2266bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2267bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
226982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
227082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
227182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
227282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
227382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
227482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
227582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2276eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
227782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
227833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
227933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
228082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2281181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
2282181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2283181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2284181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2285181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2286181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2287dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2288009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2289009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2290dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2291dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2292dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2293009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2294009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2295009b3712ff1657fa839049826451321fdd938d32Mark Wei
2296181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
2297181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Editable body = mBodyView.getEditableText();
2298181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2299181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2300181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2301181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2302181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2303181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2304181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2305181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2306181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2307181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2308181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2309181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2310181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2311181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2312181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2313181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2314181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2315181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2316181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2317181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2318181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2319181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2320181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2321181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2322181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2323181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2324181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2325181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2326181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2327181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2328181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23290bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
2330181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
2331181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged);
2332181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2333181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2334181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2335181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2336181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2337181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2338181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
2339181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
2340181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2341181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2342181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2343181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2344181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2345181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2346181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2347181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2348181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2349181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
2350181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
2351181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2352181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2353181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2354181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
2355181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
2356181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2357181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2358181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2359181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
2361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
2362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2363181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2364181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2365181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        sendOrSave(body, save, showToast, false);
2367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
23735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2379181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2381181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
2397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
23986edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .setNegativeButton(R.string.cancel, this)
23996edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .show();
2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2418181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2423e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
242405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
242544a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
242644a6339dd80f4b5b9e5d54567021698d92467c5emindyp            ReplyFromAccount draftAccount) {
2427b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
242829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2429b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2430c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2431e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2432e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2433e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
243429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
24358960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
243692551d057965689f1952faeb06763f0762bc717fMindy Pereira
2437e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2438b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2439b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
244005b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
244129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
244229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
244329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2444e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2445e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2446e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2447e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
244855271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
244955271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
245055271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
245112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2452e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
245329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2454e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2455e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2456e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2457e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
245829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
245929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2460002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
246112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2462c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2463c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2464c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2465c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2466c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2467c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2468c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2469c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2470c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2471c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2472c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2473c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2474c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2475e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
247612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
247712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
247812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
24793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
24803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
248144a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
248244a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
248382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
248882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
249182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2492b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2493b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2494b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2495b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2496b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2497b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2498b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2499b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2500b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2501b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2502002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2503002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2504002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2505002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2506002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2507002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2508002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2509002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2510002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2511002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2512002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2513002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2514002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2515002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2516002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2517002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2518002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2519002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2520002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
2521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void sendOrSave(Spanned body, boolean save, boolean showToast,
2522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            boolean orientationChanged) {
2523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
25253ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2526181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2527181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
252882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2529181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
2530181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2531181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2532181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2533181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2534181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2535181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2536181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
253782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
25391f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
254082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
254182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25420bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
254382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2544181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2545181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2546181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2547181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2548181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2549181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2550181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2551181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2556181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
255882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25590bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
25607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
25617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
256344a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
25667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
25677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
25687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
25737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
257682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25770bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
25787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
25797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
25807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
25817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
25827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
258382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25840bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
25857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
258647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
258747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
258847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
258947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
25907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
25917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
25927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
25937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
25947ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
25957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
25967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
25977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
25987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
25997ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
260082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
26027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
26037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
26047ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
26057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
26067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
260782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
26097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
26107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
26117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
26137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
26147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2618181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
261992551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
2620181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
2621181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
2622181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
2623181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
262492551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
2625181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
2626181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2629181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2630181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2631181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2633181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2634181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2635e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
263605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
263705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
263844a6339dd80f4b5b9e5d54567021698d92467c5emindyp                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount);
2639181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2640181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
2641181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
2642181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2643b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
2644181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2645181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2646181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2647181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2648181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2649181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2650181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2651181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2652181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2653181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2654181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2655181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2656181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2657181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2660181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2661181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2662181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2664181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2666181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2667181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2668181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2669181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2670181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2671181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
267282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26732db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2674013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2675013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2676d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
26772db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2678013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2681013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2682013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2683ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2684a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2685ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2686cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2687ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2688ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2689ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2690326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2691326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2692a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2693326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2694326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2695326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2696326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2697326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2698326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2699326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2700cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2701a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2702154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
270368c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
27040aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
27058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2706ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2707ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2708ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2709ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2710ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
27118960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2712ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2713ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
27148960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
27158960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
271668c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
271768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
27189b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
271968c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2720ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2721ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2722a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2723ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2724cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2725326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2726326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2727326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2728b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2729b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2730154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2731154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2732154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2733154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2734154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2735154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2736154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2737154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2738154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2739154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2740154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2741154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2742154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2743154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2744154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2745154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2746154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2747154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2748154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2749154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2750154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2751154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2752326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2753326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2754326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2755326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2756326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2757326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2758326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2759326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2760326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2761326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2762326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2763326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2764326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2765326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2766326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2767326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2768326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2769326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2770326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2771326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2772326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2773326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2774326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2775326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2776326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
277746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
277846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
277946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
278046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
278140882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
27821623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
278309dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
27848654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
278509dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
278646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
278746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
278846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
278946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
279046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
279146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
279246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
279346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
279446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
279546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2796eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
279746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
279846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
279946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
280046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
280146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
280246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
280346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
280446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
280546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2806bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
280746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
280846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
280946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
281046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2811eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2812bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2813bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2814bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2815bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2816bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2817bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2818b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2819433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
28202708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
28212708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
2822b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
28232708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
2824b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2825b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2826b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2827b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2828b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2829433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2830433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2831433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2832bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2833bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2834bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2835bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2836bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2837bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2838bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2839bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2840bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
284146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
28421a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
28435a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
28445a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
284592551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
284692551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2847f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
2848f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
2849f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
2850f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
2851f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
2852f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
2853f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
2854f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
2855f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
2856f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
2857b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2858f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
2859181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2860181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2861181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2862181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2863181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2864181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2865181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2866181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
286782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
28681a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
286982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
287082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
287182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
287282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
287382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
287482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
287582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
287682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
287782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
287882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
287982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
288082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
288182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
288282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
288382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
288482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
288582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
288682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
288782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
288882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
288982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
289082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
289182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
289282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
289382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
289482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
289582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
289682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
289782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
289882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
289982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
290082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
290182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2902efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2903efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2904efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2905efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2906efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2907efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
290882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
290982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
291082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
291182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
291282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
291382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
291482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
291582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
29167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
291782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
291882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2919b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
292078ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
2921cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2922cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
29230bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
2924cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
292582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
292682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
292782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
292882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
292982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
293082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
293182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
293282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
293382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
293482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
293582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
293682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
293782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
293882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
293982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
294082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
294182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
294282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2943eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
2944eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2945eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2946eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2947eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2948eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2949eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2950eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2951eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
295248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
2953eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2954eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2955eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2956eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
2957eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
2958eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
295940882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
296040882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
296140882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
2962eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
2963eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
296475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
296540882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
296640882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
296740882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
296840882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
296940882430c874ff29890ec6fa31f7649788cbc470mindyp    }
297075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
297175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
297275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
297375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
29740bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
297575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
297675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
297775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
297875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
297975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
298075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
298175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
298275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
298375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
298475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
29850bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
298675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
298775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
298875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
298975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
299075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
299175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
299275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
299375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
299475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
299575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
299675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
299775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
299875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
299975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
300075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
300175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
300275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
300375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
300475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
300575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
300675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
300775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
300875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
300975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
301075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
301175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
301275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
301375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
301475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
301575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
301675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
301775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
301875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
301975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
302075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
302175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
302275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
302375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
302475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
302575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
302675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
302775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
302875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
302975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
303075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
303175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
303275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
303375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
303475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
303575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
303675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
303775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
303875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
303975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
304075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
304175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
304275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
304375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
304475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
304575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
304675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
304775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
304875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
304975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
305075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
305175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
305275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
305375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
305475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
305575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
305675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
305775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
305875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
305975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
306075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
306175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
306275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
306375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
306475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3065e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3066e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3067e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3068e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3069e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3070e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3071e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3072bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3073bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3074bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3075bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3076bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
307796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
307896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
307996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
308096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
308196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
308296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
308396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3084b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3085b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3086b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
308796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
308896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
308996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
309096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
309196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
309296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3093b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3094b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3095b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case REFERENCE_MESSAGE_LOADER:
3096b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3097b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3098b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3099b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
31000aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                    initFromRefMessage(action);
3101b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finishSetup(action, intent, null, true);
3102b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (action != FORWARD) {
3103b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3104b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
31050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
31060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3107b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3108b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3109b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3110b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3111b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3112b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3113b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
311496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3115b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3116b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3117b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3118b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3119b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3120faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3121faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3122b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3123b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3124dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3125b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3126b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3127b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3128b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3129b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3130b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3131b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3132b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3133faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3134faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3135faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3136b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3137b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3138b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3139b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3140b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3141b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3142b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3143b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3144b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3145b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3146b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3147b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3148b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3149b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3150b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3151b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
315296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3153b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3154b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3155b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
315696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
315796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
315896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3159b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3160b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3161b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3162b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3163b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3164b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3165b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.addToBackStack(null);
3166b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3167b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3168b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3169b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3170b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3171b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
317296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
317396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
317496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
317596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
317683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
317783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
317883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
317983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
318083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
31811f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3182