ComposeActivity.java revision 8654d4fcc09ba68872e677b2a57877a46d27fdb5
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;
6162d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo;
62326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
638e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
64433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
656349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
66013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
677b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
68c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
695c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
7140882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
729932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
735a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
7430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
7533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
7630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
7730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
7847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
793ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8192551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
82181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
8330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
843ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
8512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
86fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
87b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
8862066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
8992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
90434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
91febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
92b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
9330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
9430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
9546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
9682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
988e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
10346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
104bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
10546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
10675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
10746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
10846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1091c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
110bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
11182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1145a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
11540882430c874ff29890ec6fa31f7649788cbc470mindyp        AttachmentAddedOrDeletedListener, OnAccountChangedListener, LoaderManager.LoaderCallbacks<Cursor>,
11662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        TextView.OnEditorActionListener {
1176349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
11836bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int COMPOSE = -1;
11936bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int REPLY = 0;
12036bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int REPLY_ALL = 1;
12136bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int FORWARD = 2;
12236bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int EDIT_DRAFT = 3;
1236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
12596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
127326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
128326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1291623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1301d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
131a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
140d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1419a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
14262066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
14362066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
15282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
15382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
15482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
15582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
15682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
15782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
15882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1641f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
16682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Key used to store the above map
16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids";
1686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
174daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
176e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
177f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1783ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
17936bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
180b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
181b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
182b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
183434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
184bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
185bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
187b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
188013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
189013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
190013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
192e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
1938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
194e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
195e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
196e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
197e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_END = null;
198e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
19996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
200b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
20147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
202b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2032db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2042db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2058e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
20682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
20782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
20882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
20982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
210c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
211c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
212c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2157b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
21633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
21792551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
218181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
21982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2206349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2216349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
222326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
223326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
22446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
22546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
22646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
227433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2281a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2292eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
230eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2311883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2321883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
233013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
234eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
23582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
23682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
23782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
23882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
23982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
240eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
241b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
242b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
24544a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
24793b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
24893b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2493ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
250326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
251daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
252daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
253daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
254cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
255cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
256cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
257b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
258b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private Bundle mSavedInstanceState;
259daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
260daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2611623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2621623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2631623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2641623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2651623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2661623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2671623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2681623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2691623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2701623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
2711623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
272daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
273326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
274326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2753ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
276bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        launch(launcher, account, message, EDIT_DRAFT);
277326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
278326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
28233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2836349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launch(launcher, account, null, COMPOSE);
2846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2876349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2890aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
2900aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
2910aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
2920aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
2930aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
2940aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
2950aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
2960aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
2970aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
2980aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
2990aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3000aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3010aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3020aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3030aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3040aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3070aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3080aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3110aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3140aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3150aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3160aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
3183ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY);
3196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3206349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3216349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3243ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
3253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY_ALL);
3266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3313ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
3323ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, FORWARD);
3336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static void launch(Context launcher, Account account, Message message, int action) {
3366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
340bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
341bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
342bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
343bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
344bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
3456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
3466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3478e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
3488e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
3498e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
3508e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
3518e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
352b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mSavedInstanceState = savedInstanceState;
353b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
354b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
355b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
356b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
357b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        Bundle savedInstanceState = mSavedInstanceState;
35846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
359818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
360e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
36162066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
36271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        boolean showQuotedText = false;
363e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
36447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
36547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
366f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (hadSavedInstanceStateMessage(savedInstanceState)) {
367e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
368e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
369e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
37062066e47fe69c33b60ed970e46809ba81d044064Mark Wei
37162066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = savedInstanceState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
372e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
373e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
37447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
375e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
376e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
377e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
37862066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
379e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
380b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
381e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
38262066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
38392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
38492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
385818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
386818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
387818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
388bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
389daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
390daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
391daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
392daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
393daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
394daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
395daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
396daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
397daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
398daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
399daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
40096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
40196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // We have a referenced message that we must look up.
40296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
40396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
40496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
405e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
406e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
407a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira            showCcBcc(savedInstanceState);
40871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira            showQuotedText = message.appendRefMessageContent;
409e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
410e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
4118960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
4128960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
413ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
414bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
415bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
416bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
417bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
418bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
419bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
420bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
421bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
422bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
423bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
424bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
425bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
426bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
427bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
428bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
429bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
430e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
43171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira            showQuotedText = message.appendRefMessageContent;
432e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
433e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
4340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
43571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira                showQuotedText = true;
436e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
4378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
4388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
439bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
44096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        finishSetup(action, intent, savedInstanceState, showQuotedText);
44196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
442bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
443b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
444faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
445faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
446b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
447b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
448faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
449b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
450b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
451b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
45226d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
453b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
454faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
455dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
456b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
457b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
458b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
459b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
460b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
461b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
462b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
463b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
464b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
465b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
466faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
467b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
468b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
469b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
470b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
47147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
47247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
47347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
47447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
47547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
47647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
47747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
4787ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
4797ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
4807ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
4817ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
4827ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
4837ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
48447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
48547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
48647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
48747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
4880617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
4890617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
4900617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
4910617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
4920617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
49347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
49447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
49547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
49647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
497b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
49847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
49947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
50047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
501b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
50247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
50347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
50447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
50547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
50647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
50747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
50847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
509b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
51047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
51147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
51247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
51347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
514b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
515b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
516b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
51747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
51847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
51947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
52047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
52147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
52296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private void finishSetup(int action, Intent intent, Bundle savedInstanceState,
52396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            boolean showQuotedText) {
52434a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
525bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
526eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
52746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
528818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
529f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
530f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
531f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
532f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
533f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
5341a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        initActionBar(action);
535e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
536e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
537d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
538d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
539d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
540d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
541d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
542d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
543d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
54475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
545326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
54671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        updateHideOrShowQuotedText(showQuotedText);
5471623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
5481623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = mSavedInstanceState != null ?
5491623f9bfde8ced840a52820da28a0939bcaa32f9mindyp                mSavedInstanceState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
5501623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
5511623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
5521623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
55371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
55471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
555f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    private boolean hadSavedInstanceStateMessage(Bundle savedInstanceState) {
556f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
557f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
558f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
55971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
56071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
56140882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
562433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
563433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
564433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
565433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
566433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
567433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
568433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
569433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
570433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
571433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
572433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
573433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
574433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
575433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
576433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
577433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
578433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
579433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
580433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
581433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
5822708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
5832708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
5842708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
5852708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
586433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
587433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
588433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
589433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
590433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
591433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
592433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
593433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
594433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
595433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
596433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
597433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
598433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
599433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
600433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
601433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
602433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
603433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
604433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
605433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
6068743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
607433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
608433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
609433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
6101a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6111a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
6121a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
6131a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
6141a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
6151a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
6161a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
617818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
618b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount, mAccounts);
619818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
6201a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6211a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
622eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
623eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
624eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
625eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
626eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
627eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
628eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
629eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
630eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
631eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
632a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
6333d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
6343d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
635a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
636a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
637eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
638eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
639eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
640eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
641b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
642eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
643b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
644b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
645b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // We were waiting for the user to create an account
646b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
647b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
648b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
649b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
650b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
651b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
652b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
653b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
654eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
655eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
656eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
657eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
658e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
65947db6d764dd4b74ddfd7fda6412e32d84d86fc9amindyp        clearChangeListeners();
660e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
661e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (savedInstanceState != null) {
662e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
663e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
664e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
665e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
666e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
667e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
668e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
669e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
670e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
671e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
672e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
673e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
6741d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        initChangeListeners();
675e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
676e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
677e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
678eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
679eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
680b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
681b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
682b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
683b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
684e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
685e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
686e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
687e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
688e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
689e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
690e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
691e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
692e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
6936273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
6946273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
695151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
696d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
697d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
698d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
699e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
700e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
701e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
702e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
703e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
704e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
705e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
706eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
707e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
708e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
709e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
710e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
711e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
712e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
713e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
714e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
715e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
716e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
717e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
718e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
7191f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
720e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
721e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
722e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
7231f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
724e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
725e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
726e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
727e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
728e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
729326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
730326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
7311623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
732816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
73362066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
73462066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
735e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
736e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
737e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
738e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
739e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
740e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
741e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
742e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
743e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
744e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
745e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
746e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
747e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
748e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
749e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
750d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
751e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
752e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
753e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
754e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
7558960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
7568960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
7578960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
7588960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
760ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindyp        String htmlBody = Html.toHtml(new SpannableString(mBodyView.getText().toString()));
761e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
762e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
763e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
764e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
765e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null;
766e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
767e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
768e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
769e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
770e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
771e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.saveUri = null;
772e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.sendUri = null;
773e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
774e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
776e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
777e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
778e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
7798960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
7808960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
7811f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
7828960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
7838960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
7848960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
785e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
7861f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
7871f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
7883c9115813343861a44133b805fb9f55512d20948Mindy Pereira    private String formatSenders(String string) {
7893c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
7903c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
7913c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
7923c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
7933c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
7943c9115813343861a44133b805fb9f55512d20948Mindy Pereira
795818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
796818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
797bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
798bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
799bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
80023e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
80123e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
802b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
803b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
80423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
805fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
806fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira            MailActivity.setForegroundNdef(MailActivity.getMailtoNdef(mAccount.name));
807fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
808818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
809818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
8119a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        String accountString = null;
812e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
81362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
81462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
815b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount, mAccounts);
8169a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
8179a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
8189a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
8199a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
8209a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
8219a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
8229a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
8239a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
824e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
825e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
826e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
827e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
828e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
829e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
830e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
83162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
83262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
833238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
83462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
8359a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
83662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
8379a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
83862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
839a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
840a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
84162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
84262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
843a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
84462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
845a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
846a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
847a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
848a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
849a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
85046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
85146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
85262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
85362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
85462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
85562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
85662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
85762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
85862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
85962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
86062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
86162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
86262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
86362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
86462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
86562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
86662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
86762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
86862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
86962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
87062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
87162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
87262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
87362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
87462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
87562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
87662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
877326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
87862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
87962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
88089bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
88162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
88262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
88362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
8845ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getToAddresses()));
8855ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getCcAddresses()));
88662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
88762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
88862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
88962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
89062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
89162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
89262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
89362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
89462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
89562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
89662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
89762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
89862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
89962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
90062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
90162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
90262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
90362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
90462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
90562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
90662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
90762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
90862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
9091617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
9101617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
9111617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
9121617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
9131617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
9141617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
91562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
91662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
91762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
91862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
91962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
92062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
92162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
92262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
92362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
92462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getDefaultReplyFromAccount(Account account) {
925238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang        for (ReplyFromAccount from : account.getReplyFroms()) {
92662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
92762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
92962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
930cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
931cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
93262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
93362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
934e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
9358960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
93662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
93762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
93862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
93962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
940cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
94162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
94262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
94362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
94562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
94662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
94762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
94962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
95062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
95162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
95246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
953b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
954a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
9558e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
9568e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
9578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
9588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
9597b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
96093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
961cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
962cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
963cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
96493b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
965cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
966cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
967cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
968818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
969818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
970818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
97182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
97282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
9736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
97462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
97546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
97646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
977433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
9781a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
9792eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
980eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
9815a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
982326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
983326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
98462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
98562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
98662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
98762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
98862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
98962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
99062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
99162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
99262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
993e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
994e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
995e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
996e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
997e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
998e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
999e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1000e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1001e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1002e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1003cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1004cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1005cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1006cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1007cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1008cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1009cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1010cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1011cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1012cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
101375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
101475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
101575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
101675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
10171d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
10181d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
101975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
102075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1021cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1022cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1023cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1024cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1025cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1026cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1027cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1028cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1029cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1030cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1031cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1032cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
103375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1034818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
103575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
103675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1037326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void initActionBar(int action) {
1038326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mComposeMode = action;
1039eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1040e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1041e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1042e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1043326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
1044eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1045eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1046326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1047eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1048326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1049326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1050326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1051eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1052eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1053326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            switch (action) {
1054326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1055eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1056326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1057326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1058eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1059326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1060326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1061eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1062326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1063326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
10646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1065fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1066fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1067fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
10686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
10696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
10700aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
10710aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
107296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
107396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
107496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
107596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
107629a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
107796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
107896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
107996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
108096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
108196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
108296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
10830aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
10848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
10858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
10868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
10878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
10888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10890aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1090e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
10918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
10928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
10936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1094c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1095c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1096e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
10971f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1098bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1099bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1100bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1101bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1102bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
1103bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
1104bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
1105bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
1106bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
11072421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
11082421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
11092421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
11105c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
11112421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
11122421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1113cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1114002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1115bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1116002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1117bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1118752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1119002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1120752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1121752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1122752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1123c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1124c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1125752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1126752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1127752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
11281a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1129c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1130002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1131002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1132bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1133752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1134752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1135752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1136752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1137752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1138002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1139752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1140752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1141002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1142002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1143002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1144002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
11453971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1146bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1147bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1148bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
11498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
11508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
11518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
11528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
11538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
11548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
11558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
11568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
11578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
11588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
11598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
11608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
11618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
11628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
11638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
11648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
11658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
11668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
11670b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
11688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
11698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
11708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1171dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
11728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
11748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
11758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
11788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
11798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
11808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
11828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
11838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
11848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
11868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
11878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
11888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
11918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
11928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
11938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
11968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
11978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
11988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1199dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
12008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1201dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
12028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1203dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
12048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
12058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
12068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
12078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
12088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
12138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
12148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
12158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
12168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
12178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1219e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1220e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
12218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
12228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1223a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1224a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1225a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
12268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
12278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
12288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
12298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String replacePlus = s.replace("+", "%2B");
1230a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
1231a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME);
1232a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1233a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1234a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1235a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1236a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1237a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1238a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1239a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
12408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
12418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
12438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
12448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
12458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
12468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
12478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
12488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
12498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
12508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
12518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
12528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
12538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
12548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
12558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
12568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
12578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
12598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1260a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1261a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1262a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
12638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
12828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
12838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME));
12848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
12858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
12878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
12928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
12938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME),
12948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
12958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
12968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
12978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1301bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1302bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1303434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1304434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1305434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1306434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1307434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1308434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1309434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1310434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1311434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1312434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1313434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1314434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1315434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1316434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1317434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1318434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1319434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1320434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1321434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1322434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
13233cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1324434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
13253cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
13263cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
13273cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
13283cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
13293cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
13303cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
13313cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1332434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1333434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1334434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1335434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
13363cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
13373cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1338434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1339434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1340434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
13413cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
13423cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
13433cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1344eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1345eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1346f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
134703ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
134803ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
134903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
135003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1351f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1352f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1353f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1354f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1355f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1356f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1357f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1358f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1359f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
13605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1361f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1362f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1363434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1364f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1365f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1366f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1367f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
13689a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
13699a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
13709a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
13719a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
13729a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
13739a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
13749a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
13759a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
13769a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
13779a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
13789a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
13799a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
13809a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
13819a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
13829a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
13839a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
13849a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
13859a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
13869a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
13879a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
13889a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1389f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
13909a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1391f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1392f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
13939a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1394f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
13959a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1396f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1397f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1398f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1399f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1400f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1401f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1402f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1403f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1404f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1405f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1406f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1407e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1408e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
14099932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
14109932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
141146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
141246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
141346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1414ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1415326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1416326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1417ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1418326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1419ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1420326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1421ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1422ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1423cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1424ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1425ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
142646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
142746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1428a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1429326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1430326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1431326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1432326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1433326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1434326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1435326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1436326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1437326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1438013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1439013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1440013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1441013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1442013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
14432421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
14442421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
14452421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
14465c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
14475c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
14482421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
14492421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1450013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
14515c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
14525c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
14535c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1454434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1455434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1456434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1457434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
14585c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
14595c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
14605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
14615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
14625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1463434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
14649932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
14659932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
14669932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1467013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
14689932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
14699932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1470434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1471013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1472013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1473013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
14740aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
14754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
14764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
14774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
14784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
147933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira        initReplyRecipients(mAccount.name, refMessage, action);
14804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
14814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1482818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
14833ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initReplyRecipients(String account, Message refMessage, int action) {
14844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // This is the email address of the current user, i.e. the one composing
14854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the reply.
14864a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira        final String accountEmail = Address.getEmailAddress(account).getAddress();
14875ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp        String[] sentToAddresses = refMessage.getToAddresses();
1488a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
148965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        String replytoAddress = refMessage.getReplyTo();
149065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
149165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (TextUtils.isEmpty(replytoAddress)) {
149265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            replytoAddress = refMessage.getFrom();
149365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
14944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
14954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
14964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
14974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1498a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1499a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
15005ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            toAddresses = initToRecipients(accountEmail, refMessage.getFrom(),
15018960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                    replytoAddress, sentToAddresses);
1502a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1503a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
15044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
15055ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            toAddresses = initToRecipients(accountEmail, refMessage.getFrom(),
15068960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                    replytoAddress, sentToAddresses);
1507154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
15084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addRecipients(accountEmail, ccAddresses, sentToAddresses);
15095ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            addRecipients(accountEmail, ccAddresses, refMessage.getCcAddresses());
15104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
15114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
15154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
15164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
15198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
15208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
15214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1523bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1524bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1525bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1526bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
15274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
15284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
15294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
15304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
15314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
15338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
15348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
15358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
15364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
15374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
15384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
15398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
15408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
15418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
15428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
15438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
15448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
15458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
15468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
15478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
15488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
15498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
15508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
15514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) {
15554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        HashSet<String> hash = new HashSet<String>();
15564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (Rfc822Token[] tokens : list) {
15574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
15584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
15594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
15604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
15624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
15654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
15664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
15674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
15694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
15704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
15724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
15754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
15764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
15774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
15784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15794a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addAddressToList(String address, RecipientEditTextView list) {
15824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
15834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
15844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
15864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
15884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
15894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
159365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp    protected Collection<String> initToRecipients(String accountEmail, String fullSenderAddress,
159465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            String replyToAddress, String[] inToAddresses) {
15954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
15964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
15974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
15984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
15994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
16004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
160165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
16023ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
16034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
160465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
160565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
160665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
160765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
160865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
160965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
161065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
161165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
161265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
161365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
161465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
161565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
161665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
161765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
161865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1619fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
16201469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
16214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
16234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1625cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    private void addRecipients(String accountAddress, Set<String> recipients, String[] addresses) {
16264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String email : addresses) {
1627cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1628cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
16294a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
16305ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
16314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
16324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
163446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
163546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1636cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1637cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1638cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1639cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1640cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param accountAddress currently selected account
1641cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1642cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1643cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
16445ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
16455ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1646fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1647cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1648cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
16493ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
16503ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
165146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
165246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
165346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
165446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
165546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
165646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
165746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
165846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
165946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
166046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
166146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1662c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1663c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
166446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
166546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
166646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
166746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
166846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
166946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
167046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
167146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1672818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1673818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1674818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1675818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1676eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1677eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1678818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1679679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
1680c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
168182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1682679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
168333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
168433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1685c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
168633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1687c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
168882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1689c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
169082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
16918e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
16928e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
16938e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
16948e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
16958e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
16968e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1697a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
16988e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
16998e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1700a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
17018e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
1702cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_photo_attachment:
1703cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_PHOTO);
1704cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
1705cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_video_attachment:
1706cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_VIDEO);
1707cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
17088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
17098e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1710b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1711b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1712b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1713b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1714b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1715b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1716b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1717b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1718b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1719b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
17201d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
17211d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
17221d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
17231d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
17241d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
17251d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
17261d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
17271d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
17281d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
17291d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
17301d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
17311d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
17321d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
17331d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
17341d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
17351d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
173682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
17371d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
17381d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        enableSave(mSavedInstanceState != null ?
17391d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                mSavedInstanceState.getBoolean(EXTRA_SAVE_ENABLED)
17401d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
17411d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
17421d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
17431d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
17441d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
174582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
17463ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
17473ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
17483ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
17493ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
17503ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
17513ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
17523ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
17533ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
17543ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
17553ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1756b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1757b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1758b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1759b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1760ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1761ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1762818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1763ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1764ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1765ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1766ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1767ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1768ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1769ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1770ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1771ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1772ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1773ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1774ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1775ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1776ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1777ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1778b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1779b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
178075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1781b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
17822db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_photo_attachment:
17832db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_PHOTO);
17842db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                break;
17852db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_video_attachment:
17862db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_VIDEO);
17877b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1788ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1789ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1790b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
179133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
179248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira                doSave(true);
179333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
179433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
179533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
179675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1797efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1798efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1799efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
18001f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
18011f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
18021f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1803fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1804daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                onAppUpPressed();
1805fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1806fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
180730745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook                Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
1808fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1809fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
181017beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook                Utils.sendFeedback(this, mAccount, false);
1811fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
181275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
181375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
181433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1815b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1816b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1817b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1818326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1819b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1820b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1821b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1822b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1823b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1824b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1825b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1826b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1827b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1828b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
18291672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
18301672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
18311672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
1832daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1833daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1834daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1835daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1836daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1837daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1838daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1839daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1840daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1841daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1842daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
18430c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
1844daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1845daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1846daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1847daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1848daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1849daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
185033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
1851dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
185233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
185333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
185448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
1855dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
185648e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
185748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
1858e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1859e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
186082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
18617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
18627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
186382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
186482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
186582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1866e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1867e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
186882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
186982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1870e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1871e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1872e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
187344a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
187482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
187644a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
187782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
187882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
187982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
188044a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
188182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
188282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
188382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
18857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
188682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
188792551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
18887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
18897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
189082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
189182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
189282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
189344a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
189444a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
189582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
189682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
189782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
189882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
1899febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
1900febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
1901febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
1902febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
1903cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1904cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1905eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
190682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
190782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
190882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
190982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
191082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
191182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
191272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount, message);
191372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
191472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
191572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
191672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
191772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
191872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
191972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
192072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
192172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
192272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
192372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
192472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
192572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
192672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
192772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
192872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        private void sendOrSaveMessage(long messageIdToSave, SendOrSaveMessage sendOrSaveMessage,
192972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                ReplyFromAccount selectedAccount, Message message) {
193072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
193172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
193272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
193372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
193472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
193572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
193672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
19373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
19383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
19393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
19403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
19413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
19423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
19433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result == null) {
19443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // TODO(pwestbro): Once Email supports the call api, remove this block
19453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If null was returned, then the provider didn't handle the call method
19463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Uri updateUri = Uri.parse(sendOrSaveMessage.mSave ?
19473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                message.saveUri : message.sendUri);
19483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        resolver.update(updateUri, sendOrSaveMessage.mValues, null, null);
19493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
195072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
19513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Uri messageUri;
19523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
19533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
19543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
19553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
19563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
19573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
19583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    } else {
19593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // TODO(pwestbro): Once Email supports the call api, remove this block
19603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = resolver.insert(
19613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri
19623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                        : selectedAccount.account.sendMessageUri,
19633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                sendOrSaveMessage.mValues);
19643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
19653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
19663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
19673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
19683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
19693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
19703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
19713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
19723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
19733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
19743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
19753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
19763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
19773c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
19783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
19793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
19803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
198172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
19823c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
19833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
19843c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
19853c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
19863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
19873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
19883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private void closeOpenedAttachmentFds(SendOrSaveMessage sendOrSaveMessage) {
19893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
19903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
19913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
19923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                for (String key : keys) {
19933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
19943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
1995ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
19963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
19973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
19983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
1999ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
20007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
20017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
200282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
200372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
200482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
200572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
200672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Use the {@link ContentResolver#call()} method to send or save the message.
200772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
200872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
200972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
201072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        private Bundle callAccountSendSaveMethod(ContentResolver resolver, Account account,
201172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                String method, SendOrSaveMessage sendOrSaveMessage) {
201272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
201372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
201472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
201572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
201672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
201772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
201872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
201972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
202072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
202172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
202272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
202372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
202472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
202572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
202672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
202772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
202872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
202972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
203072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
203182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
203272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
20343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
20353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
20363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
20373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
20383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
204072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
204182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
204282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
204382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2044e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2045e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
204692551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
204782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
20483ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2049e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2050e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
205182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
20523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
205382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
20543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
20553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
205682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
205782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
205882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
205982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
206082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
20613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
206382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
206482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
206582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
206682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
206782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
20683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
20703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
20713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
20723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
20743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
20753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
20763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
20773c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
20783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private Bundle initializeAttachmentFds(Context context, List<Attachment> attachments) {
20793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
20803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
20813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20823c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
20843c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
20853c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
20873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
20883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
20893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
20903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
20923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
20933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
20943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
20953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
20963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
20973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
20983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
20993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
21003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
21013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
21053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
210682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
210782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
210882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
210982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
211082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
211182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
211282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
211382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
211482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
211582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
211682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
211782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
211882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
211982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
212082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
212182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
212282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
212382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
212482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
212682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
212782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
212882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
212982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
213182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
213382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
213482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
213582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
213682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
213782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
213882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
213982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
214082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
214182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
214282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
214382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
214482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
214582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
214682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
214782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) {
2148e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2149e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2150e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
215182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (String email : to) {
215282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
215382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
215482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
215582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
215682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
215782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
215882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
215982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
216082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
216182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
216282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
216382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
216482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
216582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
216682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
216782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
216882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
216982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
217082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
217182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
217282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
21730bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                            @Override
217482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
217582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
217682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
217782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
217882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
217982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
218082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
218182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
218282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
218382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
218482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
218582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
218682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
218782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
218882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
218982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
219082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2191eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
219282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
219382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
219782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
219882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
219982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
22017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
220282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2206a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2207d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2208a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2213bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2218bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2219bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2220bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2221bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2222bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2223bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2224bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2225bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2226bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2227bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2228bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2229bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2230bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2231bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2232bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2233bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2234bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2235bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2236bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2237bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2238bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2239bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2240bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2241bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2242bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2243bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2244bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2245bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2246bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2247bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
224882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
225482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
225582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2256eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
225782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
225833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
225933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
226082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2261181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
2262181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2263181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2264181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2265181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2266181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2267dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2268009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2269009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2270dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2271dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2272dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2273009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2274009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2275009b3712ff1657fa839049826451321fdd938d32Mark Wei
2276181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
2277181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Editable body = mBodyView.getEditableText();
2278181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2279181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2280181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2281181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2282181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2283181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2284181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2285181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2286181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2287181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2288181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2289181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2290181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2291181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2292181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2293181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2294181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2295181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2296181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2297181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2298181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2299181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2300181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2301181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2302181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2303181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2304181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2305181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2306181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2307181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2308181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23090bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
2310181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
2311181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged);
2312181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2313181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2314181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2315181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2316181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2317181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2318181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
2319181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
2320181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2321181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2322181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2323181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2324181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2325181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2326181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2327181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2328181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2329181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
2330181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
2331181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2332181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2333181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2334181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
2335181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
2336181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2337181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2338181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2339181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2340181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
2341181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
2342181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2343181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2344181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2345181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2346181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        sendOrSave(body, save, showToast, false);
2347181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2348181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2349181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2350181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2351181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2352181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
23535c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2354181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2355181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2356181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2357181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2358181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2359181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2363181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2364181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2365181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
2370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
2371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
2372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
2373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
23786edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .setNegativeButton(R.string.cancel, this)
23796edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .show();
2380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2381181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2403e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
240405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
240544a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
240644a6339dd80f4b5b9e5d54567021698d92467c5emindyp            ReplyFromAccount draftAccount) {
240729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        ContentValues values = new ContentValues();
240829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2409c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2410c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2411e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2412e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2413e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
241429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
24158960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
241692551d057965689f1952faeb06763f0762bc717fMindy Pereira
2417e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2418ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindyp        String htmlBody = Html.toHtml(new SpannableString(body.toString()));
241905b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
242029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
242129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
242229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2423e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2424e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2425e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2426e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
242755271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
242855271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
242955271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
243012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2431e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
243229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2433e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2434e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2435e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2436e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
243729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
243829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2439002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
244012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2441c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2442c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2443c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2444c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2445c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2446c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2447c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2448c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2449c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2450c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2451c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2452c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2453c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2454e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
245512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
245612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
245712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
24583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
24593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
246044a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
246144a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
246282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2466181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
246782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
247082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2471002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2472002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2473002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2474002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2475002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2476002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2477002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2478002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2479002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2480002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2481002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2482002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2483002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2484002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2485002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2486002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2487002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2488002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2489002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
2490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void sendOrSave(Spanned body, boolean save, boolean showToast,
2491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            boolean orientationChanged) {
2492181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2493181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
24943ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2495181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2496181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
249782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2498181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
2499181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2500181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2501181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2502181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2503181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2504181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2505181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
250682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2507181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
25081f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
250982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
251082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25110bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
251282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2513181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2514181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2515181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2517181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2520181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2525181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2526181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
252782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25280bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
25297ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
25307ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2531181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
253244a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2533181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2534181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
25357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
25367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
25377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2540181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2541181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
25427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2543181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2544181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
254582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25460bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
25477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
25487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
25497ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
25507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
25517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
255282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25530bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
25547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
255547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
255647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
255747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
255847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
25597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
25607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
25617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
25627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
25637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
25647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
25657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
25667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
25677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
25687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
256982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
25717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
25727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
25737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
25747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
25757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
257682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
25787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
25797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
25807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
25817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
25827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
25837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
25847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
258892551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
2589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
2590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
2592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
259392551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
2594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
2595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2597181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2598181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2601181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2603181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2604e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
260505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
260605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
260744a6339dd80f4b5b9e5d54567021698d92467c5emindyp                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount);
2608181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
2610181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
2611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2612b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
2613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2615181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2618181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2619181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2620181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2621181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2622181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2623181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2624181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2625181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2626181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2629181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2630181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2631181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2633181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2634181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2635181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2636181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2637181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2638181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2639181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2640181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
264182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26422db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2643013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2644013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2645d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
26462db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2647013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2648181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2649181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2650013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2651013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2652ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2653a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2654ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2655cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2656ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2657ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2658ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2659326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2660326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2661a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2662326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2663326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2664326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2665326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2666326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2667326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2668326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2669cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2670a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2671154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
267268c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
26730aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
26748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2675ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2676ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2677ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2678ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2679ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
26808960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2681ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2682ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
26838960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
26848960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
268568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
268668c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
26879b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
268868c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2689ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2690ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2691a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2692ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2693cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2694326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2695326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2696326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2697b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2698b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2699154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2700154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2701154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2702154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2703154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2704154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2705154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2706154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2707154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2708154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2709154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2710154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2711154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2712154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2713154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2714154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2715154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2716154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2717154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2718154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2719154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2720154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2721326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2722326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2723326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2724326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2725326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2726326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2727326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2728326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2729326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2730326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2731326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2733326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2734326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2735326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2736326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2737326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2738326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2739326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2740326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2741326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2742326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2743326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2744326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2745326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
274646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
274746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
274846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
274946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
275040882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
27511623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
275209dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
27538654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
275409dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
275546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
275646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
275746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
275846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
275946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
276046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
276146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
276246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
276346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
276446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2765eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
276646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
276746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
276846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
276946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
277046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
277146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
277246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
277346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
277446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2775bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
277646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
277746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
277846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
277946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2780eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2781bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2782bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2783bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2784bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2785bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2786bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2787b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2788433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
27892708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
27902708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
2791b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
27922708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
2793b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2794b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2795b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2796b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2797b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2798433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2799433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2800433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2801bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2802bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2803bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2804bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2805bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2806bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2807bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2808bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2809bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
281046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
28111a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
28125a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
28135a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
281492551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
281592551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2816f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
2817f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
2818f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
2819f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
2820f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
2821f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
2822f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
2823f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
2824f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
2825f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
2826b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2827f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
2828181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
283682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
28371a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
283882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
283982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
284082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
284182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
284282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
284382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
284482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
284582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
284682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
284782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
284882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
284982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
285082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
285182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
285282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
285382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
285482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
285582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
285682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
285782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
285882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
285982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
286082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
286182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
286282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
286382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
286482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
286582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
286682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
286782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
286882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
286982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
287082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2871efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2872efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2873efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2874efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2875efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2876efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
287782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
287882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
287982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
288082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
288182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
288282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
288382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
288482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
28857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
288682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
288782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2888b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
288978ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
2890cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2891cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
28920bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
2893cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
289482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
289582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
289682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
289782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
289882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
289982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
290082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
290182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
290282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
290382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
290482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
290582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
290682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
290782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
290882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
290982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
291082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
291182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2912eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
2913eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2914eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2915eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2916eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2917eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2918eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2919eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2920eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
292148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
2922eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2923eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2924eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2925eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
2926eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
2927eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
292840882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
292940882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
293040882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
2931eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
2932eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
293375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
293440882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
293540882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
293640882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
293740882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
293840882430c874ff29890ec6fa31f7649788cbc470mindyp    }
293975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
294075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
294175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
294275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
29430bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
294475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
294575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
294675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
294775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
294875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
294975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
295075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
295175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
295275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
295375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
29540bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
295575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
295675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
295775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
295875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
295975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
296075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
296175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
296275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
296375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
296475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
296575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
296675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
296775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
296875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
296975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
297075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
297175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
297275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
297375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
297475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
297575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
297675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
297775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
297875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
297975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
298075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
298175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
298275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
298375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
298475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
298575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
298675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
298775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
298875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
298975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
299075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
299175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
299275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
299375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
299475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
299575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
299675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
299775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
299875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
299975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
300075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
300175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
300275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
300375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
300475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
300575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
300675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
300775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
300875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
300975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
301075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
301175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
301275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
301375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
301475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
301575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
301675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
301775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
301875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
301975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
302075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
302175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
302275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
302375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
302475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
302575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
302675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
302775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
302875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
302975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
303075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
303175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
303275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
303375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3034e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3035e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3036e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3037e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3038e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3039e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3040e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3041bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3042bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3043bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3044bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3045bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
304696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
304796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
304896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
304996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
305096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
305196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
305296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3053b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3054b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3055b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
305696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
305796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
305896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
305996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
306096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
306196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3062b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3063b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3064b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case REFERENCE_MESSAGE_LOADER:
3065b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3066b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3067b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3068b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
30690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                    initFromRefMessage(action);
3070b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finishSetup(action, intent, null, true);
3071b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (action != FORWARD) {
3072b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3073b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
30740aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
30750aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3076b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3077b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3078b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3079b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3080b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3081b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3082b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
308396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3084b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3085b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3086b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3087b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3088b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3089faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3090faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3091b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3092b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3093dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3094b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3095b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3096b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3097b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3098b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3099b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3100b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3101b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3102faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3103faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3104faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3105b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3106b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3107b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3108b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3109b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3110b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3111b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3112b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3113b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3114b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3115b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3116b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3117b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3118b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3119b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3120b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
312196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3122b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3123b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3124b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
312596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
312696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
312796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3128b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3129b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3130b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3131b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3132b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3133b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3134b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.addToBackStack(null);
3135b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3136b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3137b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3138b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3139b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3140b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
314196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
314296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
314396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
314496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
31451f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3146