18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/**
28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc.
38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License.
68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at
78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software
118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and
148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License.
158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */
168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose;
188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener;
215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
252558b509117872e539a6eaeb72aa63425529d50bTony Mantlerimport android.app.DialogFragment;
26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment;
27b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction;
2896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager;
296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
3296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader;
3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader;
3682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
37bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sappersteinimport android.content.res.Resources;
387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor;
441ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable;
4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
48ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString;
4982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
50c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
5182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
5246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
53c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
543cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity;
5562d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent;
56326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
58b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
59b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
63b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection;
6462d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo;
65326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
67433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
69013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
707b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
71c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
729f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantlerimport com.android.common.contacts.DataUsageStatUpdater;
735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
745680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService;
755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
76761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huangimport com.android.mail.analytics.Analytics;
771ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView;
7840882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
799932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
805a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
8130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
8233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
8330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
8430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
855680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
873ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8992551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
90181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
9130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
923ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
9312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
941ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
96fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
97b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
99434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
100febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
101b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
10230e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
10330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
10446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
113bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
11446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1181c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
119bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
12082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
12146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
12246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1232558b509117872e539a6eaeb72aa63425529d50bTony Mantler        RespondInlineListener, TextWatcher,
124a990a715012379451344246c5156d29938f12886Alice Yang        AttachmentAddedOrDeletedListener, OnAccountChangedListener,
125a990a715012379451344246c5156d29938f12886Alice Yang        LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
126a990a715012379451344246c5156d29938f12886Alice Yang        FeedbackEnabledActivity {
1276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
128bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int COMPOSE = -1;
129bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int REPLY = 0;
130bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int REPLY_ALL = 1;
131bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int FORWARD = 2;
132bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int EDIT_DRAFT = 3;
1336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
13596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
137326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
138326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1391623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1401d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
141a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
150bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
151bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Expected to be html formatted text.
152bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
153bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private static final String EXTRA_QUOTED_TEXT = "quotedText";
154bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
155d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1569a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
15762066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
15862066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
160184ec73e169fa7c54e7f3c9459191dbe1702f3b4Tony Mantler    @VisibleForTesting
161184ec73e169fa7c54e7f3c9459191dbe1702f3b4Tony Mantler    protected static final String EXTRA_TO = "to";
1628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
16560847256c691b2677772a46919038f9c600fecf7Scott Kennedy    /**
16660847256c691b2677772a46919038f9c600fecf7Scott Kennedy     * An optional extra containing a {@link ContentValues} of values to be added to
16760847256c691b2677772a46919038f9c600fecf7Scott Kennedy     * {@link SendOrSaveMessage#mValues}.
16860847256c691b2677772a46919038f9c600fecf7Scott Kennedy     */
16960847256c691b2677772a46919038f9c600fecf7Scott Kennedy    public static final String EXTRA_VALUES = "extra-values";
17060847256c691b2677772a46919038f9c600fecf7Scott Kennedy
1718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
172bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC,
173bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            EXTRA_QUOTED_TEXT };
1748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
17582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
17682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
17782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
17882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
17982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
18182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
18282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
18382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
18482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
18582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
18682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1871f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
18882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
1896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
195daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
197e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
198f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1995680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    /** If set, we will clear notifications for this folder. */
2005680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder";
2015680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
2023ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
20336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
204b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
205b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
206b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
207434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
208bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
209bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
2104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
211b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
212013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
213013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
214013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
2158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
216e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
2178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
218e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
219e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
220e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
221176a1993ab15298de58f0cc988939b2cc1632689Paul Westbrook    private static final String EXTRA_FOCUS_SELECTION_END = "focusSelectionEnd";
222e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
22396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
224b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
225a990a715012379451344246c5156d29938f12886Alice Yang    private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
22647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
227b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2282db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2292db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2308e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2319f855d667e34fbf0d330845225c26956e540b819Andy Huang    private static final String KEY_INNER_SAVED_STATE = "compose_state";
2329f855d667e34fbf0d330845225c26956e540b819Andy Huang
23382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
23482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
23582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
23682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
237c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
238c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
239c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2418e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2427b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
243746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    protected Account mAccount;
24459e69095bd558a1e6ae890ce79b7b848331d0cc6Tony Mantler    protected ReplyFromAccount mReplyFromAccount;
245181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
249326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
250746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    protected int mComposeMode = -1;
25146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
25246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
25359e69095bd558a1e6ae890ce79b7b848331d0cc6Tony Mantler    protected EditText mBodyView;
2541a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2552eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
256eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2571883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2581883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
259013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
26182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
26282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
26382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
26482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
265b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
266b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
26944a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
27193b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
27293b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2733ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
274326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
275daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
276daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
277daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
278cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
279cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
280cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
281b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
282a990a715012379451344246c5156d29938f12886Alice Yang    private boolean mShowQuotedText = false;
283746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    protected Bundle mInnerSavedState;
28460847256c691b2677772a46919038f9c600fecf7Scott Kennedy    private ContentValues mExtraValues = null;
285daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2861623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2871623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2881623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2891623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2901623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2911623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2921623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2931623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2941623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2951623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
296dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang    private boolean mPerformedSendOrDiscard = false;
2971623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
298daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
299326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
300326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
3013ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
30260847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, EDIT_DRAFT, null, null, null, null,
30360847256c691b2677772a46919038f9c600fecf7Scott Kennedy                null /* extraValues */);
304326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
305326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
30933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
31060847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, null, COMPOSE, null, null, null, null, null /* extraValues */);
3116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3126349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3136349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3146349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3156349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3163de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    public static void composeToAddress(Context launcher, Account account, String toAddress) {
31760847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, null, COMPOSE, toAddress, null, null, null,
31860847256c691b2677772a46919038f9c600fecf7Scott Kennedy                null /* extraValues */);
319bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
320bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
321bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
322bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Can be called from a non-UI thread.
323bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
324bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static void composeWithQuotedText(Context launcher, Account account,
32560847256c691b2677772a46919038f9c600fecf7Scott Kennedy            String quotedText, String subject, final ContentValues extraValues) {
32660847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, null, COMPOSE, null, null, quotedText, subject, extraValues);
3273de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    }
3283de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein
3293de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    /**
3303de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     * Can be called from a non-UI thread.
3313de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     */
332746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    public static void composeWithExtraValues(Context launcher, Account account,
333746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            String subject, final ContentValues extraValues) {
334746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein        launch(launcher, account, null, COMPOSE, null, null, null, subject, extraValues);
335746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    }
336746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein
337746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    /**
338746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein     * Can be called from a non-UI thread.
339746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein     */
3400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
3410aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
3420aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
3430aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3440aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3450aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3460aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3470aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3480aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3490aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3500aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3510aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3520aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3530aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3540aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3550aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3560aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3576d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        updateActionIntent(account, messageUri, action, intent);
3586d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3596d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        return intent;
3606d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    }
3616d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3626d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    @VisibleForTesting
3636d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    static Intent updateActionIntent(Account account, Uri messageUri, int action, Intent intent) {
3640aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3650aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3660aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3670aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3680aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3700aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3710aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3720aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3730aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3740aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3753ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
37660847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, REPLY, null, null, null, null, null /* extraValues */);
3776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
38360847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, REPLY_ALL, null, null, null, null,
38460847256c691b2677772a46919038f9c600fecf7Scott Kennedy                null /* extraValues */);
3856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3876349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3903ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
39160847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, FORWARD, null, null, null, null, null /* extraValues */);
3926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3941ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    public static void reportRenderingFeedback(Context launcher, Account account, Message message,
3951ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String body) {
396bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, FORWARD,
39760847256c691b2677772a46919038f9c600fecf7Scott Kennedy                "android-gmail-readability@google.com", body, null, null, null /* extraValues */);
3981ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    }
3991ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
4001ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    private static void launch(Context launcher, Account account, Message message, int action,
40160847256c691b2677772a46919038f9c600fecf7Scott Kennedy            String toAddress, String body, String quotedText, String subject,
40260847256c691b2677772a46919038f9c600fecf7Scott Kennedy            final ContentValues extraValues) {
4036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
4046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
4056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
4066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
407bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
408bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
409bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
410bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
411bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
4121ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (toAddress != null) {
4131ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_TO, toAddress);
4141ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
4151ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (body != null) {
4161ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_BODY, body);
4171ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
418bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        if (quotedText != null) {
419bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            intent.putExtra(EXTRA_QUOTED_TEXT, quotedText);
420bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        }
421bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        if (subject != null) {
422bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            intent.putExtra(EXTRA_SUBJECT, subject);
423bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        }
42460847256c691b2677772a46919038f9c600fecf7Scott Kennedy        if (extraValues != null) {
42560847256c691b2677772a46919038f9c600fecf7Scott Kennedy            LogUtils.d(LOG_TAG, "Launching with extraValues: %s", extraValues.toString());
42660847256c691b2677772a46919038f9c600fecf7Scott Kennedy            intent.putExtra(EXTRA_VALUES, extraValues);
42760847256c691b2677772a46919038f9c600fecf7Scott Kennedy        }
4286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
4296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
4308e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
4318e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
432d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected void onCreate(Bundle savedInstanceState) {
4338e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
4348e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
4359f855d667e34fbf0d330845225c26956e540b819Andy Huang        mInnerSavedState = (savedInstanceState != null) ?
4369f855d667e34fbf0d330845225c26956e540b819Andy Huang                savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
437b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
438b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
439b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
440b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
4419f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle savedState = mInnerSavedState;
44246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
443818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
444e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
44562066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
446a990a715012379451344246c5156d29938f12886Alice Yang        mShowQuotedText = false;
447bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        CharSequence quotedText = null;
448e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
44947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
45047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
4519f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (hadSavedInstanceStateMessage(savedState)) {
4529f855d667e34fbf0d330845225c26956e540b819Andy Huang            action = savedState.getInt(EXTRA_ACTION, COMPOSE);
4539f855d667e34fbf0d330845225c26956e540b819Andy Huang            account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
4549f855d667e34fbf0d330845225c26956e540b819Andy Huang            message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
45562066e47fe69c33b60ed970e46809ba81d044064Mark Wei
4569f855d667e34fbf0d330845225c26956e540b819Andy Huang            previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
4579f855d667e34fbf0d330845225c26956e540b819Andy Huang            mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
458bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            quotedText = savedState.getCharSequence(EXTRA_QUOTED_TEXT);
45944d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy
46044d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy            mExtraValues = savedState.getParcelable(EXTRA_VALUES);
461e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
46247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
463e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
464e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
465e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
46662066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
467e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
468b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
4694fe0af81874976a1995191321e35c844b2229811Andy Huang
4704fe0af81874976a1995191321e35c844b2229811Andy Huang            if (Analytics.isLoggable()) {
4714fe0af81874976a1995191321e35c844b2229811Andy Huang                if (intent.getBooleanExtra(Utils.EXTRA_FROM_NOTIFICATION, false)) {
4724fe0af81874976a1995191321e35c844b2229811Andy Huang                    Analytics.getInstance().sendEvent(
4734fe0af81874976a1995191321e35c844b2229811Andy Huang                            "notification_action", "compose", getActionString(action), 0);
4744fe0af81874976a1995191321e35c844b2229811Andy Huang                }
4754fe0af81874976a1995191321e35c844b2229811Andy Huang            }
476e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
47762066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
47892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
47992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
480818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
481818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
482818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
483bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
484fe853d3427119202562519c2add6873590851705Scott Kennedy        initRecipients();
485fe853d3427119202562519c2add6873590851705Scott Kennedy
4865680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
4875680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
4885680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
4895680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4905680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4915680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
492d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
49348cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
49448cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder);
4955680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4965680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4975680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4985680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
499daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
500daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
501daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
502daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
503daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
504daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
505daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
506daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
507daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
508daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
509daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
51096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
511a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = true;
512a990a715012379451344246c5156d29938f12886Alice Yang            mComposeMode = action;
513a990a715012379451344246c5156d29938f12886Alice Yang            getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
51496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
51596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
516e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
517e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
5189f855d667e34fbf0d330845225c26956e540b819Andy Huang            showCcBcc(savedState);
519a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
520bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // if we should be showing quoted text but mRefMessage is null
521bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // and we have some quotedText, display that
522746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            if (mShowQuotedText && mRefMessage == null) {
523746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                if (quotedText != null) {
524746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                    initQuotedText(quotedText, false /* shouldQuoteText */);
525746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                } else if (mExtraValues != null) {
526746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                    initExtraValues(mExtraValues);
527746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                    return;
528746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                }
529bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            }
530e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
531e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
5328960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
5338960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
534ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
535bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
536bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
537bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
538bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
539bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
540bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
541bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
542bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
543bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
544bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
545bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
546bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
547bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
548bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
549bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
550bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
551a990a715012379451344246c5156d29938f12886Alice Yang            LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
552a990a715012379451344246c5156d29938f12886Alice Yang
553a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
554a990a715012379451344246c5156d29938f12886Alice Yang            if (message.refMessageUri != null) {
555a990a715012379451344246c5156d29938f12886Alice Yang                // If we're editing an existing draft that was in reference to an existing message,
556a990a715012379451344246c5156d29938f12886Alice Yang                // still need to load that original message since we might need to refer to the
557a990a715012379451344246c5156d29938f12886Alice Yang                // original sender and recipients if user switches "reply <-> reply-all".
558a990a715012379451344246c5156d29938f12886Alice Yang                mRefMessageUri = message.refMessageUri;
559a990a715012379451344246c5156d29938f12886Alice Yang                mComposeMode = action;
560a990a715012379451344246c5156d29938f12886Alice Yang                getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
561a990a715012379451344246c5156d29938f12886Alice Yang                return;
562a990a715012379451344246c5156d29938f12886Alice Yang            }
563e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
564e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
5650aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
566a990a715012379451344246c5156d29938f12886Alice Yang                mShowQuotedText = true;
567e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
5688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
569746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            if (initFromExtras(intent)) {
570746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein                return;
571746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            }
572bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
573a990a715012379451344246c5156d29938f12886Alice Yang
574a990a715012379451344246c5156d29938f12886Alice Yang        mComposeMode = action;
5759f855d667e34fbf0d330845225c26956e540b819Andy Huang        finishSetup(action, intent, savedState);
57696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
577bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
578b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
579faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
580faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
581b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
582b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
583faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
584b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
585b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
586b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
58726d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
588b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
589faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
590dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
591b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
592b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
593b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
594b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
595b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
596b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
597b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
598b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
599b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
600b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
601faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
602b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
603b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
604b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
605b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
60647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
60747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
60847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
60947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
61047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
61147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
61247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
6137ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
6147ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
6157ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
6167ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
6177ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
6187ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
61947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
6205ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
6215ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
6225ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
62347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
62447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
6250617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
6260617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
6270617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
6280617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
6290617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
63047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
63147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
63247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
63347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
634b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
63547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
63647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
63747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
638b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
63979b1156803585952a4851221dc9fa9974e606433Tony Mantler                    if (a.getEmailAddress().equals(accountExtra)) {
64047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
64147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
64247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
64347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
64447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
64547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
646b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
64747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
64847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
64947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
65047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
651b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
652b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
653b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
65447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
65547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
65647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
65747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
65847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
659746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    protected void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
66034a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
661f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
662f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
663f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
664f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
665f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
666a990a715012379451344246c5156d29938f12886Alice Yang        initActionBar();
667e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
668e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
669d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
670d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
671d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
672d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
673d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
674d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
675d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
67675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
677326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
678a990a715012379451344246c5156d29938f12886Alice Yang        updateHideOrShowQuotedText(mShowQuotedText);
6791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
6809f855d667e34fbf0d330845225c26956e540b819Andy Huang        mRespondedInline = mInnerSavedState != null ?
6819f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
6821623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
6831623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
6841623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
68571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
68671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
687ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) {
688f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
689f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
690f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
69171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
69271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
69340882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
694433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
695433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
696433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
697433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
698433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
699433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
700433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
701433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
702433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
703433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
704433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
705433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
706433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
707433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
708433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
709433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
710433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
711433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
712433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
713433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
7142708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
7152708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
7162708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
7172708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
718ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                //$FALL-THROUGH$
719433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
720433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
721433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
722433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
723433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
724433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
725433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
726433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
727433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
728433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
729433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
730433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
731433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
732433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
733433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
734433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
735433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
736433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
737433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
738433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
7398743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
740433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
741433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
742433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
7431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
7441a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
7451a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
746761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    protected void onStart() {
747761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        super.onStart();
748761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
749761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        Analytics.getInstance().activityStart(this);
750761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    }
751761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
752761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    @Override
753761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    protected void onStop() {
754761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        super.onStop();
755761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
756761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        Analytics.getInstance().activityStop(this);
757761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    }
758761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
759761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    @Override
7601a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
7611a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
7621a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
7631a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
764818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
765c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromSpinner.initialize(mComposeMode, mAccount, mAccounts, mRefMessage);
766818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
7671a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
7681a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
769eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
770eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
771eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
772eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
773a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
7743d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
7753d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
776a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
777dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
778e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang            if (isFinishing() && !mPerformedSendOrDiscard && !isBlank()) {
779dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                // log saving upon backing out of activity. (we avoid logging every sendOrSave()
780dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                // because that method can be invoked many times in a single compose session.)
781dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                logSendOrSave(true /* save */);
782dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            }
783a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
784eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
785eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
786eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
787eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
788b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
789eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
790b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
791b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
792a990a715012379451344246c5156d29938f12886Alice Yang            // We were waiting for the user to create an account
793b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
794b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
795b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
796b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
797b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
798b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
799b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
800b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
801eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
802eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
803eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
804eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
805d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected final void onRestoreInstanceState(Bundle savedInstanceState) {
8067bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        final boolean hasAccounts = mAccounts != null && mAccounts.length > 0;
8077bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
8087bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            clearChangeListeners();
8097bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
8119f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (mInnerSavedState != null) {
8129f855d667e34fbf0d330845225c26956e540b819Andy Huang            if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
8139f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
8149f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
815e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
816e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
820e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
821e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
8247bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
8257bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            initChangeListeners();
8267bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
827e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
828e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
829e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
830d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected final void onSaveInstanceState(Bundle state) {
831eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
8329f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle inner = new Bundle();
8339f855d667e34fbf0d330845225c26956e540b819Andy Huang        saveState(inner);
8349f855d667e34fbf0d330845225c26956e540b819Andy Huang        state.putBundle(KEY_INNER_SAVED_STATE, inner);
8359f855d667e34fbf0d330845225c26956e540b819Andy Huang    }
8369f855d667e34fbf0d330845225c26956e540b819Andy Huang
8379f855d667e34fbf0d330845225c26956e540b819Andy Huang    private void saveState(Bundle state) {
838b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
839b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
840b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
841b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
842e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
843e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
848e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
849e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
850e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
8516273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
8526273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
853151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
854d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
855d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
856d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
857e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
858e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
859e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
860e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
861e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
862e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
863e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
864eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
865e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
866e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
867e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
868e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
869e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
870e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
871e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
872e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
873e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
874e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
875e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
876e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
8771f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
878e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
879e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
880e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
8811f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
882e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
883e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
884e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
885e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
886bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        } else if (message.appendRefMessageContent) {
887bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // If we have no ref message but should be appending
888bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // ref message content, we have orphaned quoted text. Save it.
889bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            state.putCharSequence(EXTRA_QUOTED_TEXT, mQuotedTextView.getQuotedTextIfIncluded());
890e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
891326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
892326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
8931623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
894816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
89562066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
89662066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
89744d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy
89844d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy        state.putParcelable(EXTRA_VALUES, mExtraValues);
899e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
900e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
901e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
902e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
903e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
904e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
905e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
906e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
907e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
908e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
909e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
910e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
911e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
912e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
913e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
914d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
915e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
916e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
917e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
918e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
9198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
9208960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
9218960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
9228960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
923e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
924b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
925b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
926e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
927e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
928e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
929a990a715012379451344246c5156d29938f12886Alice Yang        message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
930e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
931e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
932e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
933e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
934e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
935e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
936e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
937e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
938e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
939e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
940e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
941bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler        final String email = selectedReplyFromAccount != null ? selectedReplyFromAccount.address
942bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler                : mAccount != null ? mAccount.getEmailAddress() : null;
943bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler        // TODO: this behavior is wrong. Pull the name from selectedReplyFromAccount.name
944bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler        final String senderName = mAccount != null ? mAccount.getSenderName() : null;
945bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler        final Address address = new Address(senderName, email);
946bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler        message.setFrom(address.pack());
9471f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
948e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
9491f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
9501f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
951ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static String formatSenders(final String string) {
9523c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
9533c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
9543c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
9553c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
9563c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
9573c9115813343861a44133b805fb9f55512d20948Mindy Pereira
958818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
959818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
960bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
961bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
962bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
96323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
96423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
965b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
966b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
96723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
968fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
96979b1156803585952a4851221dc9fa9974e606433Tony Mantler            MailActivity.setNfcMessage(mAccount.getEmailAddress());
970fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
971818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
972818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
973e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
974e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
97562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
97662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
977c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook        mFromSpinner.initialize(action, mAccount, mAccounts, mRefMessage);
978c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook
9799a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
9809a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
9819a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
9829a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
9839a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
984c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook                final String accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
9859a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
9869a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
987e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
988e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
989e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
990e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
991e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
992e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
993e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
996238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
9989a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
99962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
10009a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
100162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
1002a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
1003a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
100462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
100562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
1006bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler            // TODO: do we want name or address here?
1007c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
100862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
1009a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
1010a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
1011bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler            // TODO: do we want name or address here?
1012c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
1013a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
1014a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
101546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
101646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
101762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
101862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
101962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
102062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
102162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
102262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
102362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
102462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
102562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
102662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
102762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
102862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
102962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
103062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
103162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
103262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
10339016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler     * Given an account and the message we're replying to,
103462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
103562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
10369016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler     * @param refMessage Message to analyze for account selection
103762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
103862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
103962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
104062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
104162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
1042326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
104362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
104462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
104589bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
104662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
104762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
104862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
10499016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            allRecipients.addAll(Arrays.asList(refMessage.getToAddressesUnescaped()));
10509016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            allRecipients.addAll(Arrays.asList(refMessage.getCcAddressesUnescaped()));
105162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
105262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
105362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
105462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
105562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
105662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
105762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
105862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
105962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
106062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
106162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
106262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
106362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
106462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
106562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
106662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
106762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
106862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
106962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
107062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
107162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
107262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
107362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
10741617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
10751617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
10761617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
10771617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
10781617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
10791617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
108062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
108162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
108262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
108362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
108462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
108562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
108662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
108762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
108862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1089ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) {
1090ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final ReplyFromAccount from : account.getReplyFroms()) {
109162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
109262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
109362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
109462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
109579b1156803585952a4851221dc9fa9974e606433Tony Mantler        return new ReplyFromAccount(account, account.uri, account.getEmailAddress(), account.name,
109679b1156803585952a4851221dc9fa9974e606433Tony Mantler                account.getEmailAddress(), true, false);
109762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
109862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1099e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
11008960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
110162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
110262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
110379b1156803585952a4851221dc9fa9974e606433Tony Mantler        if (TextUtils.equals(account.getEmailAddress(), sender)) {
110479b1156803585952a4851221dc9fa9974e606433Tony Mantler            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri,
110579b1156803585952a4851221dc9fa9974e606433Tony Mantler                    mAccount.getEmailAddress(), mAccount.name, mAccount.getEmailAddress(),
110679b1156803585952a4851221dc9fa9974e606433Tony Mantler                    true, false);
110762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
110862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
110979b1156803585952a4851221dc9fa9974e606433Tony Mantler                if (TextUtils.equals(fromAccount.address, sender)) {
111062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
111162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
111262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
111362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
111462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
111562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
111662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
111762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
111846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
1119b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
1120a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
11218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
11228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
11238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
11248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
11257b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
112693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
1127cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
1128cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
1129cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
113093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
1131cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
1132cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
1133cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
1134818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
113541500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mTo.setTokenizer(new Rfc822Tokenizer());
1136818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
113741500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mCc.setTokenizer(new Rfc822Tokenizer());
1138818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
113941500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mBcc.setTokenizer(new Rfc822Tokenizer());
114082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
114182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
11426349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
114362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
114446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
114546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
1146433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
11471a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
11482eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1149eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
11505a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1151326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1152326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
115362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
115462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
115562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
115662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
115762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
115862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
115962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
116062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
116162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1162e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1163e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1164e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1165e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1166e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1167e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1168e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1169e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1170e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1171e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1172cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1173cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1174cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1175cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1176cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1177cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1178cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1179cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1180cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1181cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
118275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
118375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
118475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
118575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
11861d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
11871d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
118875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
118975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1190cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1191cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1192cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1193cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1194cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1195cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1196cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1197cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1198cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1199cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1200cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1201cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
120275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1203818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
120475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
120575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1206a990a715012379451344246c5156d29938f12886Alice Yang    private void initActionBar() {
1207a990a715012379451344246c5156d29938f12886Alice Yang        LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
1208eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1209e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1210e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1211e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1212a990a715012379451344246c5156d29938f12886Alice Yang        if (mComposeMode == ComposeActivity.COMPOSE) {
1213eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1214eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1215326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1216eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1217326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1218326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1219326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1220eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1221eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1222a990a715012379451344246c5156d29938f12886Alice Yang            switch (mComposeMode) {
1223326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1224eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1225326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1226326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1227eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1228326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1229326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1230eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1231326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
12336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1234fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1235fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1236fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
12376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
12386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
12390aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
12400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
12411ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
12421ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // Check if To: address and email body needs to be prefilled based on extras.
12431ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // This is used for reporting rendering feedback.
12441ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
12451ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            Intent intent = getIntent();
12461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            if (intent.getExtras() != null) {
12471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String toAddresses = intent.getStringExtra(EXTRA_TO);
12481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (toAddresses != null) {
12491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
12501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
12511ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String body = intent.getStringExtra(EXTRA_BODY);
12521ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (body != null) {
12531ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    setBody(body, false /* withSignature */);
12541ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
12551ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            }
12561ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
12571ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
125896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
125996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
126096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
126196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
126229a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
126396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
126496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
126596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
126696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
126796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
126896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
12690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12750aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1276e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
12796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1280c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1281c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1282e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
12831f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1287bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1288bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
12899016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        final List<String> toAddresses = Arrays.asList(message.getToAddressesUnescaped());
1290bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
12919016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        addCcAddresses(Arrays.asList(message.getCcAddressesUnescaped()), toAddresses);
12929016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        addBccAddresses(Arrays.asList(message.getBccAddressesUnescaped()));
12932421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
12942421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
12952421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
12965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
12972421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
12982421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1299cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1300002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1302002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1303bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1304752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1305002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1306752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1307752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1308752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1309c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1310c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1311752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1312752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1313752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
13141a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1315c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1316002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1317002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1318bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1319752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1320752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1321752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1322752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1323752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1324002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1325752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1326752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1327002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1328002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1329002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1330002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
13313971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1332bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1333bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1334bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
13358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
13368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
13378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
13388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
13398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
13408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
13418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
1344746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein     * @return {@code true} if the activity should not call {@link #finishSetup}.
13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
1346746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    public boolean initFromExtras(Intent intent) {
13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
13508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
13518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
13528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
13538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13540b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
13568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
13578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1358dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
13598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
13608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
13788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
13798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
13808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
13838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
13858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1386dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
13878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1388dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1390dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
13918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
13928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
13938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
13948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
1395bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                } else if (EXTRA_QUOTED_TEXT.equals(extra)) {
1396bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                    initQuotedText(value, true /* shouldQuoteText */);
13978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
13988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
14028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
14038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
14048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
14058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
14068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1407bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1408bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // TODO - support EXTRA_HTML_TEXT
14098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1410746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein
1411746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein        mExtraValues = intent.getParcelableExtra(EXTRA_VALUES);
1412746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein        if (mExtraValues != null) {
1413746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            LogUtils.d(LOG_TAG, "Launched with extra values: %s", mExtraValues.toString());
1414746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            initExtraValues(mExtraValues);
1415746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein            return true;
1416746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein        }
1417746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein
1418746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein        return false;
1419746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    }
1420746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein
1421746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    protected void initExtraValues(ContentValues extraValues) {
1422746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein        // DO NOTHING - Gmail will override
1423e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1424e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
1425bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
14268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
14278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1428a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1429a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1430a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
14318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
14328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
14338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
1434a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
14357dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee            return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME);
1436a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1437a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1438a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1439a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1440a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1441a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1442a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1443a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
14448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
14458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
14477dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from
14487dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * changing '+' into ' '
14497dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     *
14507dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @param toReplace Input string
14517dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @return The string with all "+" characters replaced with "%2B"
14527dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     */
14533b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static String replacePlus(String toReplace) {
14547dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee        return toReplace.replace("+", "%2B");
14557dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    }
14567dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee
14577dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    /**
14588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
14598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
14608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
14618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
14628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
14638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
14648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
14658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
14668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
14678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
14688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
14698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
14708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
14718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
14728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
14738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
14748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1475a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1476a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1477a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
14788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
14798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
14808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
14818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
14828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
14838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
14878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
14888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
14908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
14918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
14938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
14948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
14968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
14978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
14987dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)),
14997dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                        UTF8_ENCODING_NAME));
15008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
15018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
15028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
15038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
15048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
15058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
15068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
15078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
15088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
15097dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME),
15108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
15118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
15128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
15138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
15148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
15158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
15168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1517bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1518bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1519434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1520434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1521434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1522434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1523434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1524434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1525434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1526434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1527434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1528434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1529434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1530434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1531434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1532434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1533434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1534434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1535434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1536434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1537434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1538434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
15393cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1540434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
15413cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
15423cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
15433cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
15443cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
15453cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
15463cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
15473cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1548434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1549434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1550434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1551434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
15523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
15533cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1554434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1555434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1556434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
15573cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
15583cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
15593cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1560eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1561eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1562f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
156303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
156403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
156503ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
156603ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1567f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1568f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1569f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1570f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1571f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1572f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1573f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1574f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1575f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
1576e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        final Attachment a = mAttachmentsView.generateLocalAttachment(uri);
1577e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        size = mAttachmentsView.addAttachment(mAccount, a);
1578e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
1579e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        Analytics.getInstance().sendEvent("send_intent_attachment",
1580e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                                Utils.normalizeMimeType(a.getContentType()), null, size);
1581e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
1582f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1583f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1584434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1585f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1586f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1587f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1588f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
15899a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
15909a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
15919a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
15929a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
15939a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
15949a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
15959a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
1596e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                            final Attachment a = mAttachmentsView.generateLocalAttachment(
1597e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                                    (Uri) uri);
1598e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                            attachments.add(a);
1599e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
1600e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                            Analytics.getInstance().sendEvent("send_intent_attachment",
1601e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                                    Utils.normalizeMimeType(a.getContentType()), null, a.size);
1602e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
16039a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
16049a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
16059a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
16069a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
16079a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
16089a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
16099a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
16109a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
16119a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
16129a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
16139a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
16149a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
16159a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1616f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
1617e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        final Attachment a = mAttachmentsView.generateLocalAttachment(uri);
1618e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        size = mAttachmentsView.addAttachment(mAccount, a);
1619e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
1620e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        Analytics.getInstance().sendEvent("send_intent_attachment",
1621e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                                Utils.normalizeMimeType(a.getContentType()), null, size);
1622e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
1623f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1624f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
16259a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1626f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
16279a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1628f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1629f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1630f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1631f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1632f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1633f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1634e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang
1635e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                Analytics.getInstance().sendEvent("send_intent_with_attachments",
1636e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang                        Integer.toString(getAttachments().size()), null, totalSize);
1637f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1638f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1639f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1640f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1641746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein    protected void initQuotedText(CharSequence quotedText, boolean shouldQuoteText) {
1642bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mQuotedTextView.setQuotedTextFromHtml(quotedText, shouldQuoteText);
1643bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mShowQuotedText = true;
1644bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
1645f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1646e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1647e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
16489932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
16499932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
165046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
165146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
165246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1653ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1654326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1655326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1656ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1657326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1658ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1659326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1660ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1661ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1662cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1663ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1664ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
166546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
166646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1667a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1668326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1669326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1670326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1671326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1672326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1673326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1674326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1675326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1676326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1677013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1678013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1679013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1680013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1681013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
16822421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
16832421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
16842421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
16855c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
16865c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
16872421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
16882421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1689013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
16905c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
16915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
16925c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1693434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1694434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1695434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1696434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
16975c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
16985c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
16995c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
17005c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
17015c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1702434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
17039932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
17049932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
17059932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1706013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
17079932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
17089932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1709434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1710013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1711013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1712013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
17130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
17144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
17154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
17164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
17174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
1718ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        initReplyRecipients(refMessage, action);
17194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17216d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // TODO: This should be private.  This method shouldn't be used by ComposeActivityTests, as
17226d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // it doesn't setup the state of the activity correctly
1723818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
1724ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    void initReplyRecipients(final Message refMessage, final int action) {
17259016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        String[] sentToAddresses = refMessage.getToAddressesUnescaped();
1726a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
172789de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String[] replyToAddresses = refMessage.getReplyToAddressesUnescaped();
172889de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        String replyToAddress = replyToAddresses.length > 0 ? replyToAddresses[0] : null;
172989de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String[] fromAddresses = refMessage.getFromAddressesUnescaped();
173089de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String fromAddress = fromAddresses.length > 0 ? fromAddresses[0] : null;
173189de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler
173265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
173389de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        if (TextUtils.isEmpty(replyToAddress)) {
173489de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            replyToAddress = fromAddress;
173565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
17364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
17384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
17394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1740a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1741a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
174289de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses);
1743a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1744a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
17454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
174689de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses);
1747154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
1748ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, sentToAddresses);
17499016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            addRecipients(ccAddresses, refMessage.getCcAddressesUnescaped());
17504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
17514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
17554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
17564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
17598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
17608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
17614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1763bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1764bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1765bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1766bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
17674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
17684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
17694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
17704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
17714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
17738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
17748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
17758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
17764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
17774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
17784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
17808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
17818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
17828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
17838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
17848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
17858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
17868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
17878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
17888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
17898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
17908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
17914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1794ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) {
1795ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final HashSet<String> hash = new HashSet<String>();
1796ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final Rfc822Token[] tokens : list) {
17974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
17984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
17994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
18004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
18014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
18024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
18034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
18044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
18054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
18064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
18074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
18084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
18094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
18104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
18114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
18124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
18134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
18144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
18154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
18164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
18174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
18184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
18194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
18204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1821ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static void addAddressToList(final String address, final RecipientEditTextView list) {
18224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
18234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
18244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1825ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
18264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
18274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
18284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
18294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
18304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
18314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
18324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
1833ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    protected Collection<String> initToRecipients(final String fullSenderAddress,
1834ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            final String replyToAddress, final String[] inToAddresses) {
18354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
18364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
18374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
18384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
18394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
18404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
184165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
18423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
18434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
184465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
184565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
184665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
184765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
184865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
184965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
185065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
185165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
185265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
185365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
185465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
185565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
185665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
185765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
185865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1859fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
18601469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
18614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
18624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
18634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
18644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1865ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void addRecipients(final Set<String> recipients, final String[] addresses) {
1866ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : addresses) {
1867cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1868cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
18694a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
18705ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
18714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
18724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
18734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
187446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
187546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1876cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1877cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1878cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1879cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1880cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1881cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1882cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
18835ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
18845ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1885fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1886cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1887cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
1888bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
1889bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Returns a formatted subject string with the appropriate prefix for the action type.
1890bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * E.g., "FWD: " is prepended if action is {@link ComposeActivity#FORWARD}.
1891bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
1892bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static String buildFormattedSubject(Resources res, String subject, int action) {
189346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
189446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
189546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
189646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
189746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
1898bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            prefix = res.getString(R.string.forward_subject_label);
189946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
1900bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            prefix = res.getString(R.string.reply_subject_label);
190146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
190246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
190346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1904c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1905c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
190646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
190746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
1908bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            correctedSubject = String.format(
1909bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                    res.getString(R.string.formatted_subject), prefix, subject);
191046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
1911bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1912bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        return correctedSubject;
1913bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
1914bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1915bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private void setSubject(Message refMessage, int action) {
1916bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mSubject.setText(buildFormattedSubject(getResources(), refMessage.subject, action));
191746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
191846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1919818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1920818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1921818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1922818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1923eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1924eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1925818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1926679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
192782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
192879b1156803585952a4851221dc9fa9974e606433Tony Mantler            final String accountName = mAccount.getEmailAddress();
192933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
193033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
193179b1156803585952a4851221dc9fa9974e606433Tony Mantler            if (offset > 0) {
193279b1156803585952a4851221dc9fa9974e606433Tony Mantler                account = account.substring(offset);
1933c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
193482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1935c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
193682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
19378e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
19388e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19398e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
19408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
19412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        final int id = v.getId();
19422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.add_cc_bcc) {
19432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Verify that cc/ bcc aren't showing.
19442b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Animate in cc/bcc.
19452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            showCcBccViews();
19462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_photo_attachment) {
19472b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_PHOTO);
19482b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_video_attachment) {
19492b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_VIDEO);
19508e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
19518e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1952b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1953b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1954b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
19555b8799a200e53e1eb66963e716b911b35bffecafTony Mantler        final boolean superCreated = super.onCreateOptionsMenu(menu);
1956b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1957b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
19585b8799a200e53e1eb66963e716b911b35bffecafTony Mantler            return superCreated;
1959b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1960b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1961b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
19621d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
19631d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
19641d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
19651d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
19661d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
19671d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
19681d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
19691d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
19701d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
19711d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
19721d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
19731d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
19741d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
19751d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
19761d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
19771d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
197882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
19791d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
19809f855d667e34fbf0d330845225c26956e540b819Andy Huang        enableSave(mInnerSavedState != null ?
19819f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
19821d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
19831d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
19841d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
19851d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
19861d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
198782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
19883ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
19893ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
19903ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
19913ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
19923ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
19933ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
19943ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
19953ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
19963ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
19973ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1998b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1999b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
2000b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
2001b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
2002ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
2003ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
2004818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
2005ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
2006ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
2007ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
2008ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
2009ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
2010ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
2011ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
2012ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
2013ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
2014ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
2015ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2016ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
2017ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2018ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2019ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
2020b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
20212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        final int id = item.getItemId();
2022dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
2023dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        Analytics.getInstance().sendMenuItemEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, id, null, 0);
2024dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
202575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
20262b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.add_photo_attachment) {
20272b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_PHOTO);
20282b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_video_attachment) {
20292b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_VIDEO);
20302b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_cc_bcc) {
20312b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            showCcBccViews();
20322b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.save) {
20332b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doSave(true);
20342b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.send) {
20352b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doSend();
20362b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.discard) {
20372b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doDiscard();
20382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.settings) {
20392b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.showSettings(this, mAccount);
20402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == android.R.id.home) {
20412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            onAppUpPressed();
20422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.help_info_menu_item) {
20432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
20442b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.feedback_menu_item) {
20452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.sendFeedback(this, mAccount, false);
20462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else {
20472b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            handled = false;
2048b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
2049b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
2050b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
2051326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2052b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
2053b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
2054b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
2055b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
2056b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
2057b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
2058b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
2059b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
2060b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
2061b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
20621672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
20631672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
20641672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
2065daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
2066daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
2067daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
2068daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
2069daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
2070daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
2071daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
2072daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2073daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
2074daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
2075daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
20760c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
2077daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
2078daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
2079daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
2080daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
2081daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
2082daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
208333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
2084dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
2085dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        logSendOrSave(false /* save */);
2086dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        mPerformedSendOrDiscard = true;
208733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
208833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
208948e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
2090dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
209148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
209248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
2093e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2094e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
209582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
20967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
20977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
209882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
209982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
210082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2101e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2102e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
210382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
210482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
2105e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
2106e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2107e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
210844a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
210982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
211082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
211144a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
211282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
211382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
211482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
211544a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
211682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
211782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
211882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
211982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
21207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
212182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
212292551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
21237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
21247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
212682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
212782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
212844a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
212944a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
213182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
213382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
2134febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
2135febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
2136febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
2137febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
2138cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
2139cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
2140eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
214182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
214282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
214382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
214482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
214582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
214682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
2147ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount);
214872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
214972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
21509f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
215172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
21529f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
215372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
21549f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
215572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
215672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
215772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
215872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
215972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
21609f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler        private static void incrementRecipientsTimesContacted(final Context context,
21619f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                final String addressString) {
21629f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            if (TextUtils.isEmpty(addressString)) {
21639f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                return;
21649f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            }
21659f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressString);
21669f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final ArrayList<String> recipients = new ArrayList<String>(tokens.length);
21679f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            for (int i = 0; i < tokens.length;i++) {
21689f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                recipients.add(tokens[i].getAddress());
21699f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            }
21709f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final DataUsageStatUpdater statsUpdater = new DataUsageStatUpdater(context);
21719f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            statsUpdater.updateWithAddress(recipients);
21729f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler        }
21739f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler
217472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
217572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
217672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2177ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private void sendOrSaveMessage(final long messageIdToSave,
2178ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) {
217972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
218072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
218172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
218272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
218372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
218472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
218572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
21863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
21873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
21883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
21893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2190013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
21913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
219272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
2193013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
21943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
21953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
21963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
21973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
21983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
21993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
22003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
22013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
22023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
22033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
22043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
22053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
22063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
22073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
22083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
22093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
22103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
22113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
22123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
22133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
22143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
22153c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
22163c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
221772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
22183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
22193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
22203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
22213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
22233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2224ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) {
22253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
22263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
22273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
2228ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                for (final String key : keys) {
22293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
22303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2231ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
22323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
22333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
22343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2235ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
22367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
22377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
223972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
224172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
2242bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein         * Use the {@link ContentResolver#call} method to send or save the message.
224372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
224472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
224572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2246ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle callAccountSendSaveMethod(final ContentResolver resolver,
2247ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final Account account, final String method,
2248ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage) {
224972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
225072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
225172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
225272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
225372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
225472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
225572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
225672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
225772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
225872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
225972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
226072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
226172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
226272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
226372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
226472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
226572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
226672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
226772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
226972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
22703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
22713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
22723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
22733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
22743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
22753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
227772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
227882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
227982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
228082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2281e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2282e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
228392551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
228482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
22853ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2286e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2287e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
228882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
22893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
229082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
22923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
229382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
229482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
229582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
229682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
22983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
230182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
230282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
230382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
230482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
23053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
23073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
23083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
23093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
23113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
23123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
23133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
23143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
2315ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle initializeAttachmentFds(final Context context,
2316ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final List<Attachment> attachments) {
23173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
23183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
23193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
23203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
23223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
23233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
23253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
23263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
23273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
23283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
23303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
23313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
23323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
23333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
23343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2335c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2336c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2337c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2338c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2339c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2340c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2341c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2342c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2343c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2344c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2345c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2346c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2347c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
23483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
23493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
23513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
23523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
23533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
23543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
23553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
23563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
235782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
235882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
235982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
236082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
236182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
236282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
236382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
236482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
236582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
236682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
236782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
236882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
236982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
237082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
237182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
237282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
237382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
237482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
237582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
237682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
237782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
237882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
237982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
238082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
238182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
238282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
238382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
238482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
238582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
238682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
238782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
238882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
238982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
239082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
239182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
239282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
239382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
239482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
239582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
239682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
239782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2398ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) {
2399e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2400e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2401e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
2402ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : to) {
240382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
240482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
240582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
240682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
240782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
240882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
24092558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class RecipientErrorDialogFragment extends DialogFragment {
2410f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        // Public no-args constructor needed for fragment re-instantiation
2411f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        public RecipientErrorDialogFragment() {}
2412f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook
24132558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static RecipientErrorDialogFragment newInstance(final String message) {
24142558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final RecipientErrorDialogFragment frag = new RecipientErrorDialogFragment();
24152558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(1);
24162558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putString("message", message);
24172558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
24182558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
24192558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
24202558b509117872e539a6eaeb72aa63425529d50bTony Mantler
24212558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
24222558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
24232558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final String message = getArguments().getString("message");
24242558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity()).setMessage(message).setTitle(
24252558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    R.string.recipient_error_dialog_title)
24262558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
24272558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(
24282558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            R.string.ok, new Dialog.OnClickListener() {
24292558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        @Override
24302558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        public void onClick(DialogInterface dialog, int which) {
24312558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            ((ComposeActivity)getActivity()).finishRecipientErrorDialog();
24322558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        }
24332558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    }).create();
24342558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
24352558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
24362558b509117872e539a6eaeb72aa63425529d50bTony Mantler
24372558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishRecipientErrorDialog() {
24382558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // after the user dismisses the recipient error
24392558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // dialog we want to make sure to refocus the
24402558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // recipient to field so they can fix the issue
24412558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // easily
24422558b509117872e539a6eaeb72aa63425529d50bTony Mantler        if (mTo != null) {
24432558b509117872e539a6eaeb72aa63425529d50bTony Mantler            mTo.requestFocus();
24442558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
24452558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
24462558b509117872e539a6eaeb72aa63425529d50bTony Mantler
244782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
244882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
244982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
245082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
24512558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showRecipientErrorDialog(final String message) {
24522558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = RecipientErrorDialogFragment.newInstance(message);
24532558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "recipient error");
245482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
245582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
245682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
245782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
245882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
245982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2460eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
246182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
246282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
246382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
246482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
246582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
246682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
246782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
246882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
246982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
24707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
247182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
247282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
247382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
247482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2475a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2476d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2477a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
247882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
247982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
248082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
248182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2482bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
248382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
248482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
248582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
2486a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang        // Need to check for null since isBlank() can be called from onPause()
2487a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang        // before findViews() is called
2488a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang        if (mSubject == null || mBodyView == null || mTo == null || mCc == null ||
2489a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang                mAttachmentsView == null) {
2490a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang            LogUtils.w(LOG_TAG, "null views in isBlank check");
2491a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang            return true;
2492a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang        }
249382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2494bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2495bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2496bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2497bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2498bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2499bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2500bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2501bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2502bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2503bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2504bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2505bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2506bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2507bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2508bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2509bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2510bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2511bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2512bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2513bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2514bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2515bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2516bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2517bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2518bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2519bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2520bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2521bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2522bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2523bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
252482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
252582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
252682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
252782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
252882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
252982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
253082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
253182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2532eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
253382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
253433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
253533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
253682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2540181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2541181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2542dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2543009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2544009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2545dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2546dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2547dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2548009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2549009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2550009b3712ff1657fa839049826451321fdd938d32Mark Wei
2551ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final String[] to, cc, bcc;
2552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2556181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2559181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2567181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2576181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2578181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2579181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2580181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
25862558b509117872e539a6eaeb72aa63425529d50bTony Mantler                boolean emptyBody = TextUtils.getTrimmedLength(mBodyView.getEditableText()) == 0;
2587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
25972558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, save,
25982558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2601181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
26032558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, save,
26042558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2608181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
26102558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showSendConfirmDialog(R.string.confirm_send_message, save, showToast);
2611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2612181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
26152558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
2616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2618181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2619181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2620181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2621181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
26225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2623181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2624181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2625181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2626181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2629181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2630181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2631181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2633181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2634181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2635181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2636181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2637181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
26382558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class SendConfirmDialogFragment extends DialogFragment {
2639f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        // Public no-args constructor needed for fragment re-instantiation
2640f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        public SendConfirmDialogFragment() {}
2641f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook
26422558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static SendConfirmDialogFragment newInstance(final int messageId,
26432558b509117872e539a6eaeb72aa63425529d50bTony Mantler                final boolean save, final boolean showToast) {
26442558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final SendConfirmDialogFragment frag = new SendConfirmDialogFragment();
26452558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(3);
26462558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putInt("messageId", messageId);
26472558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("save", save);
26482558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("showToast", showToast);
26492558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
26502558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
2651181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
26522558b509117872e539a6eaeb72aa63425529d50bTony Mantler
26532558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
26542558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
26552558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final int messageId = getArguments().getInt("messageId");
26562558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean save = getArguments().getBoolean("save");
26572558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast = getArguments().getBoolean("showToast");
26582558b509117872e539a6eaeb72aa63425529d50bTony Mantler
26592558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
26602558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(messageId)
26612558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setTitle(R.string.confirm_send_title)
26622558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
26632558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.send,
26642558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
2665aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy                                @Override
26662558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int whichButton) {
26672558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).finishSendConfirmDialog(save,
26682558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                            showToast);
26692558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
26702558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
26712558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
26722558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
26732558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
26742558b509117872e539a6eaeb72aa63425529d50bTony Mantler
26752558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishSendConfirmDialog(final boolean save, final boolean showToast) {
26762558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
26772558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
26782558b509117872e539a6eaeb72aa63425529d50bTony Mantler
26792558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showSendConfirmDialog(final int messageId, final boolean save,
26802558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast) {
26812558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = SendConfirmDialogFragment.newInstance(messageId, save,
26822558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showToast);
26832558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "send confirm");
2684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2707e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
270805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
270944a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
271060847256c691b2677772a46919038f9c600fecf7Scott Kennedy            ReplyFromAccount draftAccount, final ContentValues extraValues) {
2711b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
271229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2713b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2714c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2715e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2716e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2717e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
271829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
27198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
272092551d057965689f1952faeb06763f0762bc717fMindy Pereira
2721e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2722b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2723b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
272405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
272529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
272629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
272729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2728e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2729e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2730e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2731e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
273255271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
273355271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
273455271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
273512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2736e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
273729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2738e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2739e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2740e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2741e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
274229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
274329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2744002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
274512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2746c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2747c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2748c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2749c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2750c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2751c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2752c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2753c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2754c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2755c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2756c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2757c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2758c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
276012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
276112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
276212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
276360847256c691b2677772a46919038f9c600fecf7Scott Kennedy        if (extraValues != null) {
276460847256c691b2677772a46919038f9c600fecf7Scott Kennedy            values.putAll(extraValues);
276560847256c691b2677772a46919038f9c600fecf7Scott Kennedy        }
27663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
27673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
276844a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
276944a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
277082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2771181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2773181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
277582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2776181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2777181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
277882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2779b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2780b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2781b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2782b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2783b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2784b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2785b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2786b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2787b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2788b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2789002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2790002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2791002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2792002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2793002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2794002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2795002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2796002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2797002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2798002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2799002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2800002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2801002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2802002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2803002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2804002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2805002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2806002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2807002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
28082558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void sendOrSave(final boolean save, final boolean showToast) {
2809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2810181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
28113ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2812181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2813181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
281482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28152558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final Spanned body = mBodyView.getEditableText();
28162558b509117872e539a6eaeb72aa63425529d50bTony Mantler
2817181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
28181f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
281982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
282082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28210bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
282282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2823181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2824181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2825181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2826181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2827181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2828181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2836181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
283782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28380bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
28397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
28407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2841181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
284244a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2843181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2844181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
28457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
28467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
28477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2848181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2849181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
28527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2853181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2854181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
285582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28560bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
28577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
28587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
28597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
28607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
28617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
286282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28630bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
28647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
286547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
286647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
286747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
286847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
28697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
28707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
28717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
28727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
28737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
28747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
28757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
28767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
28777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
28787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
287982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
28817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
28827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
28837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
28847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
28857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
288682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28877ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
28887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
28897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
28907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
28917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
28927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
28937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
28947ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2895181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2896181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
28971e05a1eedd720aac611c6402c3655ec92c23a43bTony Mantler        setAccount(mReplyFromAccount.account);
2898181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2899181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2900181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2901181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2902181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2903181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2904181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2905181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2906e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
290705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
290805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
290960847256c691b2677772a46919038f9c600fecf7Scott Kennedy                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount, mExtraValues);
2910181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2911181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2912181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2913181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2914181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2915181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2916181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2917181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2918181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2919181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2920181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2921181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2922181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2923181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2924181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2925181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2926181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2927181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2928181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2929181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2930181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2931181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2932181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2933181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2934181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2935181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2936181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2937181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
293882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
29392db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2940013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2941013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2942d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
29432db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2944013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2945181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2946181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2947013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2948013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2949ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2950a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2951ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2952cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2953ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2954ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2955ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
29564fe0af81874976a1995191321e35c844b2229811Andy Huang    private static String getActionString(int action) {
2957dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final String msgType;
29584fe0af81874976a1995191321e35c844b2229811Andy Huang        switch (action) {
2959dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case COMPOSE:
2960dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "new_message";
2961dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2962dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case REPLY:
2963dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "reply";
2964dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2965dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case REPLY_ALL:
2966dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "reply_all";
2967dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2968dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case FORWARD:
2969dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "forward";
2970dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2971dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            default:
2972dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "unknown";
2973dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2974dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        }
29754fe0af81874976a1995191321e35c844b2229811Andy Huang        return msgType;
29764fe0af81874976a1995191321e35c844b2229811Andy Huang    }
29774fe0af81874976a1995191321e35c844b2229811Andy Huang
29784fe0af81874976a1995191321e35c844b2229811Andy Huang    private void logSendOrSave(boolean save) {
29794fe0af81874976a1995191321e35c844b2229811Andy Huang        if (!Analytics.isLoggable() || mAttachmentsView == null) {
29804fe0af81874976a1995191321e35c844b2229811Andy Huang            return;
29814fe0af81874976a1995191321e35c844b2229811Andy Huang        }
29824fe0af81874976a1995191321e35c844b2229811Andy Huang
29834fe0af81874976a1995191321e35c844b2229811Andy Huang        final String category = (save) ? "message_save" : "message_send";
29844fe0af81874976a1995191321e35c844b2229811Andy Huang        final int attachmentCount = getAttachments().size();
29854fe0af81874976a1995191321e35c844b2229811Andy Huang        final String msgType = getActionString(mComposeMode);
2986dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final String label;
2987dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final long value;
2988dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        if (mComposeMode == COMPOSE) {
2989dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            label = Integer.toString(attachmentCount);
2990dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            value = attachmentCount;
2991dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        } else {
2992dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            label = null;
2993dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            value = 0;
2994dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        }
2995dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        Analytics.getInstance().sendEvent(category, msgType, label, value);
2996dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang    }
2997dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
2998326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2999326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
3000a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
3001326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
3002326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
3003326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
3004326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
3005326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
3006326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
3007326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
3008cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
3009a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
3010154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
301168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
30120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
30138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
3014ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
3015ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
3016ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
3017ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
3018ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
30198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
3020ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
3021ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
30228960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
30238960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
302468c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
302568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
30269b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
302768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
3028ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
3029ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
3030a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
3031ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
3032cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
3033326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
3034326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
3035326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3036b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
3037b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
3038154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
3039154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
3040154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
3041154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
3042154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
3043154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
3044154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
3045154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
3046154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
3047154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
3048154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
3049154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
3050154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
3051154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
3052154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
3053154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
3054154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
3055154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
3056154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
3057154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
3058154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
3059154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
3060326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
3061326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3062326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
3063326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3064326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
3065326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
3066326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
3067326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
3068326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3069326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
3070326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
3071326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
3072326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
3073326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
3074326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
3075326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3076326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
3077326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
3078326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
3079326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
3080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
3081326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
3082326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
3083326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
3084326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
308546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
308646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
308746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
308846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
308940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
30901623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
309109dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
30928654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
309309dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
309446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
309546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
309646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
309746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
309846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
309946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
310046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
310146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
310246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
310346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
3104eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
310546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
310646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
310746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
310846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
310946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
311046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
311146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
311246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
311346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
3114bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
311546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
311646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
311746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
311846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
3119eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
3120bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
3121bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
3122bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
3123bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
3124bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
3125bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
3126b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
3127433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
31282708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
31292708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
3130b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
31312708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
3132b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
3133b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
3134b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
3135b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
3136b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
3137433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
3138433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
3139433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
3140bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
3141bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
3142bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
3143bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
3144bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
3145bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
3146bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
3147bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
3148bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
314946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
31501a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
31515a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
31525a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
315392551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
315492551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
3155f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
3156f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
3157f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
3158f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
3159f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
3160f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
3161f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
3162f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
3163f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
3164f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
3165b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
3166f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
3167181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
3168181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
3169181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
3170181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
3171181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
3172181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
3173181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
3174181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
317582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
31761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
317782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
317882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
317982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
318082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
318182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
318282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
318382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
31842558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class DiscardConfirmDialogFragment extends DialogFragment {
3185f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        // Public no-args constructor needed for fragment re-instantiation
3186f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        public DiscardConfirmDialogFragment() {}
3187f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook
31882558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
31892558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
31902558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
31912558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(R.string.confirm_discard_text)
31922558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.discard,
31932558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
31942558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                @Override
31952558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int which) {
31962558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).doDiscardWithoutConfirmation();
31972558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
31982558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
31992b215b7e4aa5901322dd6ef2e4e8616a4552e9b3Tony Mantler                    .setNegativeButton(R.string.cancel, null)
32002558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
320182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
320282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
320382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3204efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
32052558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = new DiscardConfirmDialogFragment();
32062558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "discard confirm");
3207efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
320882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
320982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
321082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
321182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
321282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
321382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
32142558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void doDiscardWithoutConfirmation() {
32157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
321682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
321782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
3218b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
321978ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
3220cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
3221cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
32220bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
3223cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
322482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
322582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
322682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
322782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
322882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
322982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
323082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
323182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
32322558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // Display a toast to let the user know
32332558b509117872e539a6eaeb72aa63425529d50bTony Mantler        Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
323482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
323582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
323682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
3237dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        mPerformedSendOrDiscard = true;
323882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
323982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
324082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3241eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
3242eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
3243eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
3244eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
3245eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
3246eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
3247eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3248eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3249eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
325048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
3251eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3252eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
3253eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3254eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
3255eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
3256eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
325740882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
325840882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
325940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
3260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
3261eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
326275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
326340882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
326440882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
326540882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
326640882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
326740882430c874ff29890ec6fa31f7649788cbc470mindyp    }
326875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
326975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
327075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
327175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
32720bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
327375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
327475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
327575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
327675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
327775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
327875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
327975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
328075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
328175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
328275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
32830bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
328475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
328575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
328675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
328775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
328875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
328975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
329075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
329175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
329275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
329375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
329475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
329575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
329675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
329775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
329875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
329975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
330075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
330175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
330275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
330375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
330475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
330575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
330675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
330775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
330875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
330975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
331075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
331175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
331275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
331375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
331475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
331575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
331675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
331775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
331875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
331975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
332075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
332175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
332275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
332375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
332475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
332575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
332675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
332775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
332875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
332975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
333075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
333175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
333275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
333375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
333475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
333575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
333675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
333775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
333875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
333975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
334075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
334175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
334275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
334375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
334475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
334575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
334675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
334775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
334875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
334975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
335075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
335175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
335275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
335375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
335475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
335575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
335675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
335775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
335875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
335975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
336075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
336175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
336275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3363e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3364e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3365e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3366e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3367e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3368e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3369e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3370bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3371bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3372bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3373bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3374bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
337596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
337696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
337796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
337896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
3379a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3380a990a715012379451344246c5156d29938f12886Alice Yang                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
3381a990a715012379451344246c5156d29938f12886Alice Yang                        null, null);
338296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
338396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
338496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3385b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3386b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3387b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
338896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
338996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
339096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
339196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
339296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
339396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3394b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3395b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3396a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3397b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3398b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3399b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3400a990a715012379451344246c5156d29938f12886Alice Yang                    initFromRefMessage(mComposeMode);
3401a990a715012379451344246c5156d29938f12886Alice Yang                    finishSetup(mComposeMode, intent, null);
3402a990a715012379451344246c5156d29938f12886Alice Yang                    if (mComposeMode != FORWARD) {
3403b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3404b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
34050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
34060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3407b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3408b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3409b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3410b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3411b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3412b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3413b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
341496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3415b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3416a990a715012379451344246c5156d29938f12886Alice Yang            case REFERENCE_MESSAGE_LOADER:
3417a990a715012379451344246c5156d29938f12886Alice Yang                // Only populate mRefMessage and leave other fields untouched.
3418a990a715012379451344246c5156d29938f12886Alice Yang                if (data != null && data.moveToFirst()) {
3419a990a715012379451344246c5156d29938f12886Alice Yang                    mRefMessage = new Message(data);
3420a990a715012379451344246c5156d29938f12886Alice Yang                }
34219f855d667e34fbf0d330845225c26956e540b819Andy Huang                finishSetup(mComposeMode, getIntent(), mInnerSavedState);
3422a990a715012379451344246c5156d29938f12886Alice Yang                break;
3423b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3424b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3425b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3426b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3427faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3428faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3429b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3430b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3431dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3432b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3433b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3434b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3435b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3436b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3437b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3438b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3439b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3440faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3441faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3442faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3443b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3444b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3445b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3446b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3447b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3448b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3449b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3450b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3451b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3452b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3453b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3454b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3455b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3456b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3457b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3458b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
345996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3460b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3461b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3462b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
346396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
346496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
346596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3466b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3467b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3468b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3469b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3470b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3471b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3472b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3473b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3474b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3475b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3476b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3477b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
347896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
347996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
348096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
348196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
348283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
348383e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
348483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
348583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
348683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
34871f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3488