ComposeActivity.java revision d47877e3860ea4249eddb3f6efefbc6cd39f2320
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
19ebc4bda7184ce659144eb95c7e73cb77ce3384daAndrew Sappersteinimport android.animation.LayoutTransition;
20326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener;
225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity;
2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
2696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager;
276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
2882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
3096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader;
3182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader;
3482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
378e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
3882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
3982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
40f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable;
4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
4482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
45c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
4682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
4746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
48c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
493cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity;
50326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
51b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
52b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
53b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
558e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
565c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
57eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection;
58326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
60433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
611f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView;
626349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
63013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
647b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
65c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
665c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
675c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
68eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener;
699932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
705a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
7130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
7233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
7330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
7430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
755ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereiraimport com.android.mail.providers.Folder;
7647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
773ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
7882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
7992551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
80181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
8130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
823ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
8312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
84fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
8592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
86b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
8730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
8830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
8946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
9082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
928e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
9362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException;
9462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
9746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
98bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
9946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
10075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
10146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
10246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1031c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
104bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
10582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
10646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
10746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1085a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
10996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        AttachmentDeletedListener, OnAccountChangedListener, LoaderManager.LoaderCallbacks<Cursor> {
1106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
11136bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int COMPOSE = -1;
11236bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int REPLY = 0;
11336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int REPLY_ALL = 1;
11436bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int FORWARD = 2;
11536bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int EDIT_DRAFT = 3;
1166349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1176349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
11896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
120326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
121326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
122a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1319a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira    private static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1329a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
1338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
14382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
14482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
14582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
14682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
14782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
14882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
14982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
15082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
15182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
15282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
15382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
15482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Key used to store the above map
15582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids";
1566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1596349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1616349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
162daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1636349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
164e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
165f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1663ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
16736bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
168b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
169b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
170b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
171bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // If this is an action to edit an existing draft messagge, this extra will hold the
172bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
173bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
175b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
176013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
177013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
178013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
180e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
1818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
182e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
183e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
184e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
185e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_END = null;
186e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
18796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
18847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
1898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
19182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
19282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
19382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
194c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
195c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
196c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
1978e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
1988e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
1997b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
20033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
20192551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
202181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
20382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
206326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
207326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
20846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
20946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
21046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
211433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2121a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2132eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
214eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2151883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2161883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
217013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
218eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
21982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
22082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
22182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
22282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
22382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
224eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
225b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
226b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
2297ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
2301f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    private ImageView mAttachmentsButton;
2313ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
233daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
234daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
235daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
236cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
237cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
238cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
239b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
240daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
241daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
242daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
243326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
244326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2453ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
246bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        launch(launcher, account, message, EDIT_DRAFT);
247326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
248326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
25233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launch(launcher, account, null, COMPOSE);
2546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2593ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
2603ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY);
2616349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2626349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2636349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2656349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2663ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
2673ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY_ALL);
2686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2733ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
2743ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, FORWARD);
2756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2766349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2773ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static void launch(Context launcher, Account account, Message message, int action) {
2786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
2796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
2806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
2816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
282bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
283bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
2876349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
2886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2908e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
2918e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
2928e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
2938e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
29446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
295818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
296e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
29771c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        boolean showQuotedText = false;
298e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
29947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
30047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
301f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (hadSavedInstanceStateMessage(savedInstanceState)) {
302e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
303e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
304e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
305e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
306e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
30747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
308e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
309e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
310e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
311e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
312b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
313e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
31492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
31592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
316818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
317818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
318818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
319bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
320daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
321daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
322daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
323daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
324daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
325daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
326daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
327daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
328daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
329daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
330daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
33196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
33296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // We have a referenced message that we must look up.
33396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
33496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
33596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
336e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
337e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
338a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira            showCcBcc(savedInstanceState);
33971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira            showQuotedText = message.appendRefMessageContent;
340e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
341e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
342ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = !TextUtils.isEmpty(message.bcc);
343ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = showBcc || !TextUtils.isEmpty(message.cc);
344ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
345bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
346bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
347bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
348bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
349bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
350bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
351bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
352bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
353bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
354bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
355bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
356bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
357bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
358bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
359bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
360bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
361e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
36271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira            showQuotedText = message.appendRefMessageContent;
363e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
364e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
365e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                initFromRefMessage(action, mAccount.name);
36671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira                showQuotedText = true;
367e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
3688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
3698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
370bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
37196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        finishSetup(action, intent, savedInstanceState, showQuotedText);
37296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
373bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
37447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
37547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
37647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
37747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
37847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
37947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
38047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
38147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
38247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
38347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
38447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
38547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            final String lastAccountUri = MailAppProvider.getInstance().getLastSentFromAccount();
38647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
38747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
38847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
38947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
39047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this);
39147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (syncingAccounts.length > 0) {
39247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
39347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
39447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
39547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                for (Account a : syncingAccounts) {
39647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
39747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
39847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
39947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
40047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
40147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
40247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
40347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                for (Account a : syncingAccounts) {
40447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
40547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
40647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
40747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
408fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira            } else {
409fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira                account = syncingAccounts[0];
41047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
41147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
41247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
41347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
41447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
41596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private void finishSetup(int action, Intent intent, Bundle savedInstanceState,
41696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            boolean showQuotedText) {
417bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
418eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
41946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
420818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
421f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
422f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
423f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
424f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
425f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
4261a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        initActionBar(action);
427e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
428e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
42975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
430433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        setFocus(action);
431326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
43271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        updateHideOrShowQuotedText(showQuotedText);
43371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
43471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
435f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    private boolean hadSavedInstanceStateMessage(Bundle savedInstanceState) {
436f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
437f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
438f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
43971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
44071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
441433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
442433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
443433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
444433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
445433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
446433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
447433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
448433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
449433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
450433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
451433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
452433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
453433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
454433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
455433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
456433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
457433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
458433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
459433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
460433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
461433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mTo.requestFocus();
462433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
463433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
464433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
465433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
466433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
467433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
468433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
469433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
470433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
471433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
472433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
473433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
474433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
475433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
476433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
477433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
478433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
479433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
480433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
481433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
482433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
483433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        } else if (length > 0) {
484433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
485433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
486433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
4871a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
4881a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
4891a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
4901a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
4911a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
4921a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
4931a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
494818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
49562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount);
496818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
4971a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
4981a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
499eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
500eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
501eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
502eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
503eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
504eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
505eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
506eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
507eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
508eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
509a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
510a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        if (isFinishing()) {
511a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
512a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
513eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
514eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
515eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
516eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
517eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAddingAttachment = false;
518eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
519eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) {
520eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
521eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
522eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
523eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
524eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
525e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
526e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
527e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (savedInstanceState != null) {
528e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
529e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
530e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
531e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
532e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
533e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
534e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
535e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
536e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
537e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
538e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
539e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
540e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
541e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
542e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
543eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
544eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
545e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
546e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
547e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
548e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
549e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
550e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
551e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
552e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
553e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
5546273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
5556273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
556151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
557d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
558d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
559d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
560e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
561e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
562e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
563e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
564e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
565e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
566e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
567eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
568e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
569e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
570e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
571e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
572e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
573e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
574e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
575e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
576e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
577e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
578e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
579e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = createMessage(selectedReplyFromAccount, mode);
580e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
581e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
582e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
583e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
584e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
585326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
586326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
587e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
588e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
589e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
590e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
591e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
592e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
593e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
594e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
595e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
596e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
597e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
598e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
599e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
600e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
601e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
602d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
603e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
604e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
605e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
606e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
6071eedc7520600a315afba4fc114a9fc5bf1adacd7Mindy Pereira        message.from = selectedReplyFromAccount != null ? selectedReplyFromAccount.address
608b67aa8f5975082434dc6b8ebeedf2f1333dbf86dMindy Pereira                : mAccount != null ? mAccount.name : null;
6093c9115813343861a44133b805fb9f55512d20948Mindy Pereira        message.to = formatSenders(mTo.getText().toString());
6103c9115813343861a44133b805fb9f55512d20948Mindy Pereira        message.cc = formatSenders(mCc.getText().toString());
6113c9115813343861a44133b805fb9f55512d20948Mindy Pereira        message.bcc = formatSenders(mBcc.getText().toString());
612e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.replyTo = null;
613e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
614e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        String htmlBody = Html.toHtml(mBodyView.getText());
615e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
616e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
617e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
618e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
619e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null;
620d2bef8b371784d95f60dd3f89aa0ac3557c945efMindy Pereira        message.draftType = getDraftType(mode);
621e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
622e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
623e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
624e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
625e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
626e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.saveUri = null;
627e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.sendUri = null;
628e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
629e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
630e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
631e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
632e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
633e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
634e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return message;
635eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
636eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
6373c9115813343861a44133b805fb9f55512d20948Mindy Pereira    private String formatSenders(String string) {
6383c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
6393c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
6403c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
6413c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
6423c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
6433c9115813343861a44133b805fb9f55512d20948Mindy Pereira
644818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
645818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
646bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
647bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
648bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
64923e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
65023e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
651b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
652b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
65323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
654fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
655fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira            MailActivity.setForegroundNdef(MailActivity.getMailtoNdef(mAccount.name));
656fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
657818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
658818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
659e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
6609a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        String accountString = null;
661e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
66262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
66362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
66462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount);
6659a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
6669a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
6679a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
6689a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
6699a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
6709a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
6719a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
6729a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
673e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
674e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
675e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
676e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
677e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
678e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
679e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
68062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
68162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
68262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
683cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
68462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
6859a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
68662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
6879a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
68862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
689a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
690a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
69162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
69262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
693a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
69462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
695a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
696a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
697a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
698a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
699a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
70046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
70146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
70262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
70362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
70462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
70562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
70662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
70762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
70862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
70962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
71062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
71162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
71262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
71362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
71462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
71562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
71662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
71762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
71862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
71962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
72062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
72162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
72262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
72362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
72462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
72562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
72662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
727326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
72862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
72962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
73089bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
73162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
73262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
73362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
73462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to)));
73562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc)));
73662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
73762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
73862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
73962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
74062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
74162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
74262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
74362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
74462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
74562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
74662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
74762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
74862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
74962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
75062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
75162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
75262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
75362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
75462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
75562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
75662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
75762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
75862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
75962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        try {
76062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            customFroms = FromAddressSpinner.getAccountSpecificFroms(account);
76162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (customFroms != null) {
76262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                for (ReplyFromAccount entry : customFroms) {
76362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    if (recipientsMap.contains(entry.address)) {
76462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                        matchingReplyFrom = entry;
76562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                        matchingAddressCount++;
76662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    }
76762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
76862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
76962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } catch (JSONException e) {
77062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s",
77162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    account.name);
77262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
77362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
77462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
77562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
77662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
77762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
77862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
77962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getDefaultReplyFromAccount(Account account) {
78062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
78162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (ReplyFromAccount from : replyFromAccounts) {
78262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
78362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
78462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
78562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
786cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
787cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
78862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
78962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
790e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
791e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        String sender = msg.from;
79262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
79362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
79462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
79562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
796cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
79762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
79862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
79962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
80062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
80162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
80262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
80362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
80462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
80562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
80662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
80762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
80846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
809a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
8108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
8118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
8128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
8138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
8147b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
815ca87d6d907e6d00670c8af607cf82cf7a73f7b39Andrew Sapperstein        LayoutTransition transition =
816ca87d6d907e6d00670c8af607cf82cf7a73f7b39Andrew Sapperstein                ((ViewGroup) findViewById(R.id.content)).getLayoutTransition();
817ca87d6d907e6d00670c8af607cf82cf7a73f7b39Andrew Sapperstein        mAttachmentsView.setComposeLayoutTransition(transition);
8181f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment);
8191f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        if (mAttachmentsButton != null) {
8201f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            mAttachmentsButton.setOnClickListener(this);
8211f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        }
822818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
823818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
824818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
82582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
82682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
8276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
82846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
82946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
830433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
8311a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
8322eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
833eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
8345a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
835326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
836326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
837e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
838e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
839e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
840e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
841e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
842e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
843e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
844e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
845e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
846e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
847cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
848cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
849cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
850cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
851cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
852cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
853cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
854cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
855cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
856cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
85775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
85875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
85975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
86075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
86175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
86275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
863cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
864cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
865cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
866cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
867cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
868cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
869cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
870cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
871cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
872cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
873cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
874cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
87575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
876818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
87775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
87875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
879326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void initActionBar(int action) {
880326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mComposeMode = action;
881eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
882e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
883e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
884e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
885326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
886eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
887eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
888326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
889eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
890326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
891326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
892326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
893eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
894eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
895326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            switch (action) {
896326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
897eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
898326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
899326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
900eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
901326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
902326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
903eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
904326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
905326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
9066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
907fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
908fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
909fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
9106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
9116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
91246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void initFromRefMessage(int action, String recipientAddress) {
91396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        setFieldsFromRefMessage(action, recipientAddress);
91496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
91596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
91696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
91796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
91829a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
91996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
92096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
92196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
92296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
92396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
92496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
92596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private void setFieldsFromRefMessage(int action, String recipientAddress) {
9268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
9278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
9288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
9298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
9308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
9318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        initRecipientsFromRefMessage(recipientAddress, mRefMessage, action);
932e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
9338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
9348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
9356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
936c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
937c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
938e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
939bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message");
940bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
941bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
942bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
943bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
944bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
945bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
946bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
947bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
948bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
9492421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
9502421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
9512421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
9525c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
9532421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
9542421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
955cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
956002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
957bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
958002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
959bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
960752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
961002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
962752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
963752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
964752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
965752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    htmlText = Html.fromHtml(message.bodyHtml.substring(0, quotedTextIndex));
966752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
967752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
968752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
969002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
970002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
971bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
972752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
973752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
974752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
975752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
976752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
977002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
978752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
979752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
980002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
981002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
982002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
983002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
9843971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
985bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
986bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
987bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
9888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
9898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
9908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
9918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
9928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
9938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
9948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
9958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
9968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
9978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
9988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
9998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
10008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
10018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
10028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
10038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
10048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
10058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
10060b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
10078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
10088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
10098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1010dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
10118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
10128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
10138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
10148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
10168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
10178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
10188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
10198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
10218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
10228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
10238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
10258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
10268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
10278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
10298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
10308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
10318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
10328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
10348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
10358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
10368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
10378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1038dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
10398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1040dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
10418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1042dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
10438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
10448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
10458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
10468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
10478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
10488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
10498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
10508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
10518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
10528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
10538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
10548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
10558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
10568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
10578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1058e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1059e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
10608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
10618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1062a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1063a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1064a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
10658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
10668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
10678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
10688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String replacePlus = s.replace("+", "%2B");
1069a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
1070a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME);
1071a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1072a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1073a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1074a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1075a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1076a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1077a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1078a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
10798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
10808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
10818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
10828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
10838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
10848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
10858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
10868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
10878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
10888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
10898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
10908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
10918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
10928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
10938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
10948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
10958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
10968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
10978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
10988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1099a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1100a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1101a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
11028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
11038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
11048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
11058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
11068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
11078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
11088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
11118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
11128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
11148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
11158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
11178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
11188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
11208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
11218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
11228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME));
11238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
11248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
11258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
11268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
11278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
11298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
11308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
11318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
11328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME),
11338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
11348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
11358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
11368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
11378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
11398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1140bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1141bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
11423cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        try {
11433cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira            mAttachmentsView.addAttachments(mAccount, refMessage);
11443cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        } catch (AttachmentFailureException e) {
11453cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
11463cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira            showAttachmentTooBigToast();
11473cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
11483cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
11493cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
11503cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
11513cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
11523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
11533cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
11543cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
11553cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    private void showAttachmentTooBigToast() {
11563cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        showErrorToast(R.string.too_large_to_attach);
11573cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
11583cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
11593cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    private void showErrorToast(int resId) {
11603cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        Toast t = Toast.makeText(this, resId, Toast.LENGTH_LONG);
11613cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setText(resId);
11623cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
11633cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
11643cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1165eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1166eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1167f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
116803ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
116903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
117003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
117103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1172f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1173f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1174f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1175f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1176f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1177f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1178f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1179f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1180f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
11815c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1182f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1183f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
11843cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                        showAttachmentTooBigToast();
1185f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1186f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1187f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1188f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1189f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) {
1190f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
1191f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                long size = 0;
1192f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                try {
11935c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                    size =  mAttachmentsView.addAttachment(mAccount, uri);
1194f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                } catch (AttachmentFailureException e) {
1195f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    LogUtils.e(LOG_TAG, e, "Error adding attachment");
11963cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                    showAttachmentTooBigToast();
1197f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1198f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                totalSize += size;
1199f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1200f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1201f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND_MULTIPLE.equals(action)
1202f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    && extras.containsKey(Intent.EXTRA_STREAM)) {
1203f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
1204f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (Parcelable uri : uris) {
1205f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1206f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
12075c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size = mAttachmentsView.addAttachment(mAccount, (Uri) uri);
1208f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1209f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
12103cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                        showAttachmentTooBigToast();
1211f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1212f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1213f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1214f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1215f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1216f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1217f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1218f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1219f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1220f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1221f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1222f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1223f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1224e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1225e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
12269932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
12279932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
122846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
122946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
123046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1231ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1232326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1233326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1234ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1235326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1236ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1237326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1238ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1239ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1240ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.GONE);
1241ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1242ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
124346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
124446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1245a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1246326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1247326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1248326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1249326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1250326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1251326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1252326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1253326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1254326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1255013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1256013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1257013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1258013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1259013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
12602421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
12612421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
12622421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
12635c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
12645c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
12652421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
12662421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1267013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
12685c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
12695c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
12705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
12713cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira            showErrorToast(R.string.generic_attachment_problem);
12725c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
12735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
12745c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
12755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
12765c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
12775c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            long size =  mAttachmentsView.addAttachment(mAccount, attachment);
12789932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
12799932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
12809932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1281013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
12829932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
12839932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
12843cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira            showAttachmentTooBigToast();
1285013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1286013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1287013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
12883ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initRecipientsFromRefMessage(String recipientAddress, Message refMessage,
128946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            int action) {
12904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
12914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
12924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
12934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
129433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira        initReplyRecipients(mAccount.name, refMessage, action);
12954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
12964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1297818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
12983ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initReplyRecipients(String account, Message refMessage, int action) {
12994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // This is the email address of the current user, i.e. the one composing
13004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the reply.
13014a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira        final String accountEmail = Address.getEmailAddress(account).getAddress();
13021469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira        String fromAddress = getAddress(refMessage.from);
13033ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to);
13043ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String replytoAddress = refMessage.replyTo;
1305a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
13064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
13084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
13094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1310a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1311a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
13123ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
13131469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira                    sentToAddresses);
1314a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1315a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
13164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
13173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
13189b18a9a10538418f0280380e81452c52f5ce2542Mindy Pereira                    sentToAddresses);
1319154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
13204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addRecipients(accountEmail, ccAddresses, sentToAddresses);
13213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            addRecipients(accountEmail, ccAddresses,
13223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    Utils.splitCommaSeparatedString(refMessage.cc));
13234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
13244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
13254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
13264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13271469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira    private String getAddress(String toParse) {
13281469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira        if (!TextUtils.isEmpty(toParse)) {
13291469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(toParse);
13301469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            if (tokens.length > 0) {
13311469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira                return tokens[0].getAddress();
13321469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
13331469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira        }
13341469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira        return "";
13351469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira    }
13361469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira
13374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
13384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
13394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
13404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
13444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
13454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1346bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1347bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1348bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1349bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
13504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
13514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
13524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
13534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
13544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
13568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
13578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
13588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
13594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
13604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
13614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
13754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
13764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) {
13784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        HashSet<String> hash = new HashSet<String>();
13794a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (Rfc822Token[] tokens : list) {
13804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
13814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
13824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
13834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
13844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
13854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
13864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
13884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
13894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
13904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
13924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
13934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
13944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
13954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
13964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
13974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
13984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
13994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
14004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
14014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
14024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
14034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
14044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addAddressToList(String address, RecipientEditTextView list) {
14054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
14064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
14074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
14084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
14094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
14104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
14114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
14124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
14134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
14144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
14154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
14164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected Collection<String> initToRecipients(String account, String accountEmail,
14173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            String senderAddress, String replyToAddress, String[] inToAddresses) {
14184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
14194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
14204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
14214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
14224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
14234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
14243ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        if (!TextUtils.isEmpty(replyToAddress)) {
14253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
14264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
1427cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            if (!recipientMatchesThisAccount(account, senderAddress)) {
14281469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira                toAddresses.add(senderAddress);
14291469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            } else {
14301469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira                // This happens if the user replies to a message they originally
14311883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira                // wrote. In this case, "reply" really means "re-send," so we
14321883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira                // target the original recipients. This works as expected even
14331883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira                // if the user sent the original message to themselves.
14341469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira                toAddresses.addAll(Arrays.asList(inToAddresses));
14351469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
14364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
14374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
14384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
14394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1440cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    private void addRecipients(String accountAddress, Set<String> recipients, String[] addresses) {
14414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String email : addresses) {
1442cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1443cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
14444a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
1445cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            if (!recipientMatchesThisAccount(accountAddress, recipientAddress)) {
14464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
14474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
14484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
144946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
145046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1451cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1452cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1453cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1454cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1455cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param accountAddress currently selected account
1456cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1457cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1458cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
1459cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    protected boolean recipientMatchesThisAccount(String accountAddress, String recipientAddress) {
1460cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira        return accountAddress.equalsIgnoreCase(recipientAddress)
1461cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira                || ReplyFromAccount.isCustomFrom(recipientAddress,
1462cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira                        mFromSpinner.getReplyFromAccounts());
1463cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1464cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
14653ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
14663ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
146746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
146846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
146946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
147046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
147146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
147246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
147346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
147446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
147546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
147646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
147746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1478c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1479c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
148046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
148146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
148246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
148346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
148446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
148546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
148646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
148746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1488818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1489818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1490818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1491818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1492eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1493eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1494818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1495679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
1496c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
149782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1498679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
149933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
150033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1501c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
150233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1503c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
150482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1505c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
150682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
15078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
15088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
15098e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
15108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
15118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
15128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1513a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
15148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
15158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1516a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
15178e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
15181f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.add_attachment:
15198f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein                openAttachmentTypeSelectionDialog();
15201f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
15218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
15228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1523b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1524b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1525b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1526b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1527b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1528b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
152982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
153082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
15313ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
15323ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
15333ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
15343ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
15353ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
15363ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
15373ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
15383ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
15393ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
15403ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1541b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1542b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1543b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1544b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1545ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1546ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1547818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1548ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1549ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1550ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1551ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1552ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1553ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1554ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1555ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1556ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1557ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1558ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
155975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        if (mSave != null) {
156075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mSave.setEnabled(shouldSave());
156175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
1562ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1563ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1564ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1565ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1566b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1567b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
156875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1569b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
15707b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira            case R.id.add_attachment:
15718f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein                openAttachmentTypeSelectionDialog();
15727b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1573ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1574ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1575b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
157633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
157748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira                doSave(true);
157833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
157933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
158033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
158175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1582efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1583efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1584efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
15851f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
15861f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
15871f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1588fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1589daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                onAppUpPressed();
1590fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1591fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
1592fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                // TODO: enable context sensitive help
1593498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook                Utils.showHelp(this, mAccount, null);
1594fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1595fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
1596fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                Utils.sendFeedback(this, mAccount);
1597fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
159875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
159975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
160033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1601b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1602b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1603b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1604326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1605daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1606daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1607daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1608daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1609daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1610daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1611daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1612daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1613daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1614daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1615daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
16165ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira        Folder defaultInbox = new Folder();
16175ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira        defaultInbox.uri = mAccount.settings.defaultInbox;
1618daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        final Intent mailIntent =
161996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                Utils.createViewFolderIntent(defaultInbox, mAccount);
1620daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1621daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1622daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1623daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1624daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1625daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1626daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
162733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
16288aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira        clearImeText();
162982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        sendOrSaveWithSanityChecks(false, true, false);
163033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
163133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
163248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
163348e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira        // Clear the IME composing suggestions from the body and subject before saving.
16348aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira        clearImeText();
1635eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        sendOrSaveWithSanityChecks(true, showToast, false);
163648e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
163748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
16388aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira    private void clearImeText() {
16398aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira        mBodyView.clearComposingText();
16408aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira        BaseInputConnection.removeComposingSpans(mBodyView.getEditableText());
16418aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira        mSubject.clearComposingText();
16428aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira        BaseInputConnection.removeComposingSpans(mSubject.getEditableText());
164382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
164482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1645e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1646e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
164782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
16487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
16497ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
165082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
165182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
165282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1653e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1654e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
165582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
165682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1657e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1658e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1659e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
166082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
166182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
166282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                SendOrSaveCallback callback) {
166382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
166482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
166582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
166682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
166782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
166882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
166982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
16707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
167182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
167292551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
16737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
16747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
167582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
167682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
167782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
16787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) {
167982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
168082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
168182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
168282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
168392551d057965689f1952faeb06763f0762bc717fMindy Pereira                    if (selectedAccount.account.expungeMessageUri != null) {
168492551d057965689f1952faeb06763f0762bc717fMindy Pereira                        resolver.update(selectedAccount.account.expungeMessageUri, values, null,
1685eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                                null);
1686cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1687cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1688eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
168982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
169082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
169182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
169282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
169382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
169482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
169582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) {
16967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
169782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mContext.getContentResolver().update(
16987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri),
16997ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sendOrSaveMessage.mValues, null, null);
170082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            } else {
17017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                ContentResolver resolver = mContext.getContentResolver();
170292551d057965689f1952faeb06763f0762bc717fMindy Pereira                Uri messageUri = resolver
170392551d057965689f1952faeb06763f0762bc717fMindy Pereira                        .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri
170492551d057965689f1952faeb06763f0762bc717fMindy Pereira                                : selectedAccount.account.sendMessageUri,
170592551d057965689f1952faeb06763f0762bc717fMindy Pereira                                sendOrSaveMessage.mValues);
17067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sendOrSaveMessage.mSave && messageUri != null) {
17077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Cursor messageCursor = resolver.query(messageUri,
17087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            UIProvider.MESSAGE_PROJECTION, null, null, null);
1709ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                    if (messageCursor != null) {
1710ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
1711ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            if (messageCursor.moveToFirst()) {
1712ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // Broadcast notification that a new message has
1713ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // been allocated
1714ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
1715ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                        new Message(messageCursor));
1716ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            }
1717ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        } finally {
1718ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            messageCursor.close();
1719ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
17207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
17217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
172282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
172382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
17247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!sendOrSaveMessage.mSave) {
172582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
17267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
172782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
17287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
172982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
17307ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
173182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
173282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
173382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
173482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
173582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
173682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Array of the outstanding send or save tasks.  Access is synchronized
173782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // with the object itself
173882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /* package for testing */
1739e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1740e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
174182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private int mRequestId;
1742bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String mSignature;
17438f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein    private AttachmentTypeSelectorAdapter mAttachmentTypeSelectorAdapter;
174482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1745e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1746e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
174792551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
174882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
17493ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
1750e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1751e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
175282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
175382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
175492551d057965689f1952faeb06763f0762bc717fMindy Pereira        public SendOrSaveMessage(ReplyFromAccount account, ContentValues values,
17553ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                String refMessageId, boolean save) {
175682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
175782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
175882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
175982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
176082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
176182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
176282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
176382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
176482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
176582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
176682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
176782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
176882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
176982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
177082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
177182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
177282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
177382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
177482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
177582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
177682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
177782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
177882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
177982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
178082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
178182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
178282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
178382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
178482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
178582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
178682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
178782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
178882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
178982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
179082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
179182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
179282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
179382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
179482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
179582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
179682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
179782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
179882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
179982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
180082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
180182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
180282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
180382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
180482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
180582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
180682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
180782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) {
1808e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
1809e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
1810e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
181182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (String email : to) {
181282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
181382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
181482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
181582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
181682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
181782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
181882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
181982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
182082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
182182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
182282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
182382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
182482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
182582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
182682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
182782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
182882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
182982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
183082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
183182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
183282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
18330bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                            @Override
183482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
183582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
183682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
183782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
183882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
183982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
184082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
184182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
184282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
184382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
184482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
184582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
184682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
184782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
184882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
184982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
185082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
1851eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
185282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
185382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
185482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
185582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
185682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
185782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
185882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
185982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
186082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
18617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
186282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
186382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
186482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
186582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
1866a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
1867d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
1868a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
186982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
187082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
187182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
187282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1873bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
187482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
187682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
187782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
1878bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
1879bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
1880bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
1881bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
1882bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
1883bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1884bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1885bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
1886bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
1887bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
1888bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1889bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
1890bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
1891bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1892bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1893bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
1894bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
1895bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
1896bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
1897bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1898bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
1899bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
1900bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
1901bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
1902bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
1903bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
1904bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
1905bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
1906bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1907bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
190882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
190982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
191082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
191182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
191282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
191382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
191482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
191582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
1916eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
191782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
191833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
191933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
192082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1921181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
1922181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
1923181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
1924181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
1925181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1926181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
1927181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            final boolean orientationChanged) {
1928181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1929181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Editable body = mBodyView.getEditableText();
1930181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1931181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1932181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1933181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1934181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1935181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1936181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1937181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1938181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
1939181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
1940181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
1941181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
1942181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1943181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1944181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1945181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
1946181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1947181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
1948181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
1949181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
1950181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1951181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1952181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
1953181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
1954181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
1955181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
1956181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
1957181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1958181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1959181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1960181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
19610bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
1962181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
1963181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged);
1964181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1965181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1966181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1967181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
1968181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1969181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
1970181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
1971181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
1972181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1973181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
1974181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
1975181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
1976181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
1977181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1978181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
1979181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
1980181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
1981181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
1982181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
1983181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1984181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1985181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1986181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
1987181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
1988181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1989181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1990181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1991181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
1992181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
1993181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
1994181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
1995181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1996181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1997181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1998181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        sendOrSave(body, save, showToast, false);
1999181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2000181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2003181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2004181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
20055c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2006181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2007181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2008181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2009181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2010181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2011181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2012181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2013181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2014181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2015181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2016181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2017181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2018181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2019181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2020181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2021181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
2022181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
2023181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
2024181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
2025181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2026181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
2027181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
2028181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
2029181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
20306edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .setNegativeButton(R.string.cancel, this)
20316edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .show();
2032181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2033181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2034181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2035181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2036181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2037181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2038181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2039181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2040181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2041181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2042181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2043181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2044181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2045181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2046181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2047181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2048181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2049181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2050181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2051181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2052181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2053181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2054181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2055e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
205605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
205705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) {
205829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        ContentValues values = new ContentValues();
205929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2060c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2061c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2062e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2063e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2064e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
206529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2066e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCustomFromAddress(values, message.from);
206792551d057965689f1952faeb06763f0762bc717fMindy Pereira
2068e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
206929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        String htmlBody = Html.toHtml(body);
207005b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
207129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
207229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
207329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2074e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2075e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2076e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2077e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
207855271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
207955271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
208055271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
208112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2082e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
208329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2084e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2085e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2086e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2087e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
208829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
208929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2090002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
209112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2092c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2093c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2094c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2095c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2096c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2097c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
2098c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2099c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2100c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2101c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
2102c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2103e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
210412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
210512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
210612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
210782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
210892551d057965689f1952faeb06763f0762bc717fMindy Pereira        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount,
2109181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                values, refMessageId, save);
2110181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback);
211182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2112181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
211382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2114181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2115181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2116181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
211782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2118181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2119181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
212082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2121002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2122002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2123002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2124002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2125002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2126002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2127002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2128002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2129002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2130002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2131002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2132002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2133002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2134002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2135002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2136002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2137002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2138002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2139002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
2140181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void sendOrSave(Spanned body, boolean save, boolean showToast,
2141181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            boolean orientationChanged) {
2142181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2143181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
21443ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2145181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2146181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
214782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2148181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
2149181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2150181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2151181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2152181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2153181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2154181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2155181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
215682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2157181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
215882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
215982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21600bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
216182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2162181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2163181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2164181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2165181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2166181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2167181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2168181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2169181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2170181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2171181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2172181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2173181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2174181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2175181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
217682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21770bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
21787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
21797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2180181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
2181181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2182181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
21837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
21847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
21857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2186181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2187181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2188181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2189181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
21907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2191181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2192181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
219382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21940bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
21957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
21967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
21977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
21987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
21997ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22010bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
22027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
220347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
220447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
220547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
220647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
22077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
22087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
22097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
22107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
22117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
22127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
22137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
22147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
22157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
22167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
22197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
22207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
22217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
22227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
22237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
22267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
22277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
22287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
22297ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
22307ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
22317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
22327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2233181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2234181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2235181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
223692551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
2237181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
2238181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
2239181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
2240181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
224192551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
2242181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
2243181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2244181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2245181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2246181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2247181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2248181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2249181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2250181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2251181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2252e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
225305b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
225405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
225512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                mSendSaveTaskHandler, save, mComposeMode);
2256181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2257181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
2258181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
2259181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2260b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
2261181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2262181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2263181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2264181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2265181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2266181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2267181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2268181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2269181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2270181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2271181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2272181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2273181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2274181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2275181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2276181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2277181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2278181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2279181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2280181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2281181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2282181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2283181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2284181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2285181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2286181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2287181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2288181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
228982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22908f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein    public void openAttachmentTypeSelectionDialog() {
22918f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein        AlertDialog.Builder builder = new AlertDialog.Builder(this);
22928f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein        builder.setTitle(R.string.add_file_attachment);
22938f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein        builder.setAdapter(new AttachmentTypeSelectorAdapter(this),
22948f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein                new DialogInterface.OnClickListener() {
22958f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein            public void onClick(DialogInterface dialog, int position) {
22968f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein                doAttach(position);
22978f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein            }
22988f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein        });
22998f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein        builder.show();
23008f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein    }
23018f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein
23028f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein    private void doAttach(int position) {
2303013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2304013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2305d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
23068f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein        i.setType(AttachmentTypeSelectorAdapter.ITEMS.get(position).mMimeType);
2307013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2308181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2309181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2310013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2311013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2312ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2313a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2314ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2315ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            mCcBccButton.setVisibility(View.GONE);
2316ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2317ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2318ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2319326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2320326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2321a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2322326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2323326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2324326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2325326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2326326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2327326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2328326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2329cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2330a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2331154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
2332ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft == null && mRefMessage != null) {
233396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                setFieldsFromRefMessage(mComposeMode, mAccount.name);
23348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2335ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2336ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2337ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2338ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2339ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
2340ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                showBcc = !TextUtils.isEmpty(mDraft.bcc);
2341ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2342ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
2343ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                showCc = showBcc || (!TextUtils.isEmpty(mDraft.cc) && mComposeMode == REPLY_ALL);
2344ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            } else if (mRefMessage != null) {
2345ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                showCc = mComposeMode == REPLY_ALL && !TextUtils.isEmpty(mRefMessage.cc);
2346ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2347ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2348a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2349ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2350cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2351326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2352326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2353326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2354b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2355b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2356154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2357154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2358154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2359154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2360154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2361154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2362154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2363154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2364154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2365154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2366154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2367154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2368154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2369154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2370154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2371154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2372154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2373154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2374154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2375154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2376154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2377154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2378326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2379326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2380326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2381326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2382326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2383326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2384326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2385326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2386326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2387326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2388326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2389326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2390326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2391326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2392326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2393326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2394326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2395326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2396326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2397326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2398326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2399326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2400326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2401326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2402326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
240346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
240446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
240546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
240646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
240746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
240846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
240946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
241046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
241146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
241246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
241346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
241446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
241546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
241646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2417eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
241846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
241946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
242046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
242146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
242246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
242346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
242446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
242546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
242646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2427bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
242846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
242946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
243046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
243146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2432eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2433bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2434bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2435bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2436bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2437bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2438bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2439b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2440433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
2441b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        if (!TextUtils.equals(newSignature, mSignature)) {
2442b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
2443b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            if (!TextUtils.isEmpty(mSignature)
2444b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                    && getSignatureStartPosition(mSignature,
2445b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                            mBodyView.getText().toString()) < 0) {
2446b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2447b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2448b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2449b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2450b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2451433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2452433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2453433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2454bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2455bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2456bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2457bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2458bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2459bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2460bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2461bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2462bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
246346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
24641a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
24655a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
24665a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
246792551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
246892551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2469b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2470b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook
2471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2474181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2475181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2476181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2477181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2478181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
247982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
24801a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
248182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
248282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
248382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
248482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
248582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
248682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
248782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
248882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
248982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
249082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
249182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
249282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
249382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
249482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
249582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
249682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
249782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
249882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
249982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
250082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
250182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
250282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
250382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
250482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
250582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
250682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
250782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
250882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
250982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
251082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
251182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
251282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
251382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2514efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2515efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2516efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2517efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2518efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2519efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
252082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
252182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
252282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
252382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
252482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
252582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
252682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
252782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
25287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
252982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
253082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2531b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
253278ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
2533cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2534cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
25350bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
2536cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
253782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
253882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
253982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
254082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
254182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
254282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
254382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
254482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
254582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
254682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
254782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
254882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
254982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
255082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
255182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
255282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
255382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
255482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2555eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
2556eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2557eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2558eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2559eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2560eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2561eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2562eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2563eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
256448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
2565eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2566eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2567eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2568eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
2569eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
2570eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
2571eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
2572eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
257375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
257475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
257575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
257675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
257775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
25780bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
257975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
258075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
258175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
258275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
258375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
258475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
258575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
258675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
258775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
258875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
25890bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
259075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
259175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
259275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
259375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
259475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
259575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
259675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
259775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
259875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
259975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
260075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
260175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
260275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
260375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
260475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
260575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
260675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
260775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
260875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
260975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
261075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
261175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
261275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
261375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
261475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
261575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
261675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
261775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
261875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
261975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
262075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
262175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
262275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
262375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
262475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
262575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
262675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
262775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
262875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
262975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
263075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
263175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
263275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
263375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
263475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
263575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
263675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
263775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
263875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
263975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
264075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
264175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
264275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
264375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
264475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
264575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
264675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
264775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
264875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
264975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
265075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
265175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
265275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
265375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
265475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
265575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
265675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
265775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
265875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
265975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
266075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
266175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
266275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
266375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
266475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
266575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
266675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
266775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
266875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
2669e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
2670e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
2671e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
2672e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
2673e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
2674e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
2675e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
2676bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
2677bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
2678bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
2679bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
2680bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
268196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
268296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
268396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
268496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
268596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
268696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
268796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
268896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
268996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
269096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
269196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
269296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
269396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
269496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (data != null && data.moveToFirst()) {
269596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            mRefMessage = new Message(data);
269696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // We set these based on EXTRA_TO.
269796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            mRefMessage.to = null;
269896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            mRefMessage.from = null;
269996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            Intent intent = getIntent();
270096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
270196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            initFromRefMessage(action, mAccount.name);
270296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            finishSetup(action, intent, null, true);
270396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            if (action != FORWARD) {
270496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                String to = intent.getStringExtra(EXTRA_TO);
270596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                if (!TextUtils.isEmpty(to)) {
270696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                    clearChangeListeners();
270796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                    mTo.append(to);
270896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                    initChangeListeners();
270996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
271096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
271196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
271296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            finish();
271396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
271496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
271596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
271696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
271796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
271896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
271996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
272096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira}