ComposeActivity.java revision 1e05a1eedd720aac611c6402c3655ec92c23a43b
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;
761ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView;
7740882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
789932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
795a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
8133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
8230e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
8330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
845680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
863ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8892551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
89181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
9030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
913ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
9212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
931ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
95fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
96b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
98434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
99febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
100b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
10130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
10230e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
10346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1068e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
11146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
112bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1171c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
118bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
11982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
12046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
12146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1222558b509117872e539a6eaeb72aa63425529d50bTony Mantler        RespondInlineListener, TextWatcher,
123a990a715012379451344246c5156d29938f12886Alice Yang        AttachmentAddedOrDeletedListener, OnAccountChangedListener,
124a990a715012379451344246c5156d29938f12886Alice Yang        LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
125a990a715012379451344246c5156d29938f12886Alice Yang        FeedbackEnabledActivity {
1266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
127bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int COMPOSE = -1;
128bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int REPLY = 0;
129bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int REPLY_ALL = 1;
130bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int FORWARD = 2;
131bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int EDIT_DRAFT = 3;
1326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
13496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
136326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
137326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1381623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1391d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
140a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
149bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
150bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Expected to be html formatted text.
151bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
152bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private static final String EXTRA_QUOTED_TEXT = "quotedText";
153bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
154d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1559a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
15662066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
15762066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
164bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC,
165bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            EXTRA_QUOTED_TEXT };
1668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
16882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
16982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
17082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
17382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
17482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
17582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
17682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
17782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
17882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1791f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
1816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1826349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1836349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
187daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
189e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
190f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1915680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    /** If set, we will clear notifications for this folder. */
1925680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder";
1935680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
1943ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
19536bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
196b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
197b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
198b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
199434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
200bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
201bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
2024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
203b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
204013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
205013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
206013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
2078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
208e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
2098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
210e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
211e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
212e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
213176a1993ab15298de58f0cc988939b2cc1632689Paul Westbrook    private static final String EXTRA_FOCUS_SELECTION_END = "focusSelectionEnd";
214e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
21596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
216b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
217a990a715012379451344246c5156d29938f12886Alice Yang    private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
21847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
219b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2202db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2212db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2239f855d667e34fbf0d330845225c26956e540b819Andy Huang    private static final String KEY_INNER_SAVED_STATE = "compose_state";
2249f855d667e34fbf0d330845225c26956e540b819Andy Huang
22582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
22682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
22782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
22882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
229c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
230c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
231c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2328e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2338e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2347b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
23533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
23692551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
237181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
23882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
241326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
242326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
24346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
24446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
245433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2461a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2472eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
248eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2491883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2501883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
251013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
252eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
25382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
25482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
25582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
25682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
257b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
258b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
26144a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
26393b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
26493b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2653ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
266326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
267daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
268daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
269daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
270cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
271cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
272cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
273b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
274a990a715012379451344246c5156d29938f12886Alice Yang    private boolean mShowQuotedText = false;
2759f855d667e34fbf0d330845225c26956e540b819Andy Huang    private Bundle mInnerSavedState;
276daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
277daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2781623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2801623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2811623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2821623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2831623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2841623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2851623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2861623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2871623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
2881623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
289daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
290326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
291326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2923ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
293bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, EDIT_DRAFT, null, null, null, null);
294326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
295326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2986349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
29933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
300bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, null, COMPOSE, null, null, null, null);
3016349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3026349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3063de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    public static void composeToAddress(Context launcher, Account account, String toAddress) {
307bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, null, COMPOSE, toAddress, null, null, null);
308bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
309bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
310bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
311bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Can be called from a non-UI thread.
312bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
313bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static void composeWithQuotedText(Context launcher, Account account,
314bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            String quotedText, String subject) {
315bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, null, COMPOSE, null, null, quotedText, subject);
3163de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    }
3173de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein
3183de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    /**
3193de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     * Can be called from a non-UI thread.
3203de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     */
3210aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
3220aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
3230aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
3240aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3250aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3260aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3270aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3280aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3290aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3300aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3310aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3320aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3330aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3360aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3370aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3386d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        updateActionIntent(account, messageUri, action, intent);
3396d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3406d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        return intent;
3416d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    }
3426d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3436d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    @VisibleForTesting
3446d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    static Intent updateActionIntent(Account account, Uri messageUri, int action, Intent intent) {
3450aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3460aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3470aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3480aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3490aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3500aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3510aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3520aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3530aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3540aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3550aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3563ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
357bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, REPLY, null, null, null, null);
3586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3596349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3616349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3626349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
364bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, REPLY_ALL, null, null, null, null);
3656349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3703ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
371bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, FORWARD, null, null, null, null);
3726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3741ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    public static void reportRenderingFeedback(Context launcher, Account account, Message message,
3751ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String body) {
376bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, FORWARD,
377bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                "android-gmail-readability@google.com", body, null, null);
3781ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    }
3791ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
3801ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    private static void launch(Context launcher, Account account, Message message, int action,
381bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            String toAddress, String body, String quotedText, String subject) {
3826349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3836349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
386bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
387bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
388bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
389bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
390bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
3911ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (toAddress != null) {
3921ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_TO, toAddress);
3931ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3941ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (body != null) {
3951ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_BODY, body);
3961ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
397bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        if (quotedText != null) {
398bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            intent.putExtra(EXTRA_QUOTED_TEXT, quotedText);
399bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        }
400bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        if (subject != null) {
401bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            intent.putExtra(EXTRA_SUBJECT, subject);
402bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        }
4036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
4046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
4058e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
4068e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
407d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected void onCreate(Bundle savedInstanceState) {
4088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
4098e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
4109f855d667e34fbf0d330845225c26956e540b819Andy Huang        mInnerSavedState = (savedInstanceState != null) ?
4119f855d667e34fbf0d330845225c26956e540b819Andy Huang                savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
412b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
413b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
414b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
415b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
4169f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle savedState = mInnerSavedState;
41746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
418818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
419e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
42062066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
421a990a715012379451344246c5156d29938f12886Alice Yang        mShowQuotedText = false;
422bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        CharSequence quotedText = null;
423e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
42447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
42547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
4269f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (hadSavedInstanceStateMessage(savedState)) {
4279f855d667e34fbf0d330845225c26956e540b819Andy Huang            action = savedState.getInt(EXTRA_ACTION, COMPOSE);
4289f855d667e34fbf0d330845225c26956e540b819Andy Huang            account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
4299f855d667e34fbf0d330845225c26956e540b819Andy Huang            message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
43062066e47fe69c33b60ed970e46809ba81d044064Mark Wei
4319f855d667e34fbf0d330845225c26956e540b819Andy Huang            previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
4329f855d667e34fbf0d330845225c26956e540b819Andy Huang            mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
433bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            quotedText = savedState.getCharSequence(EXTRA_QUOTED_TEXT);
434e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
43547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
436e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
437e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
438e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
43962066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
440e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
441b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
442e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
44362066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
44492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
44592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
446818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
447818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
448818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
449bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
450fe853d3427119202562519c2add6873590851705Scott Kennedy        initRecipients();
451fe853d3427119202562519c2add6873590851705Scott Kennedy
4525680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
4535680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
4545680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
4555680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4565680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4575680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
458d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
45948cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
46048cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder);
4615680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4625680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4635680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4645680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
465daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
466daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
467daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
468daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
469daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
470daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
471daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
472daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
473daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
474daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
475daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
47696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
477a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = true;
478a990a715012379451344246c5156d29938f12886Alice Yang            mComposeMode = action;
479a990a715012379451344246c5156d29938f12886Alice Yang            getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
48096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
48196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
482e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
483e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
4849f855d667e34fbf0d330845225c26956e540b819Andy Huang            showCcBcc(savedState);
485a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
486bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // if we should be showing quoted text but mRefMessage is null
487bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // and we have some quotedText, display that
488bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            if (mShowQuotedText && quotedText != null && mRefMessage == null) {
489bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                initQuotedText(quotedText, false /* shouldQuoteText */);
490bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            }
491e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
492e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
4938960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
4948960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
495ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
496bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
497bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
498bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
499bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
500bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
501bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
502bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
503bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
504bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
505bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
506bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
507bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
508bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
509bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
510bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
511bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
512a990a715012379451344246c5156d29938f12886Alice Yang            LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
513a990a715012379451344246c5156d29938f12886Alice Yang
514a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
515a990a715012379451344246c5156d29938f12886Alice Yang            if (message.refMessageUri != null) {
516a990a715012379451344246c5156d29938f12886Alice Yang                // If we're editing an existing draft that was in reference to an existing message,
517a990a715012379451344246c5156d29938f12886Alice Yang                // still need to load that original message since we might need to refer to the
518a990a715012379451344246c5156d29938f12886Alice Yang                // original sender and recipients if user switches "reply <-> reply-all".
519a990a715012379451344246c5156d29938f12886Alice Yang                mRefMessageUri = message.refMessageUri;
520a990a715012379451344246c5156d29938f12886Alice Yang                mComposeMode = action;
521a990a715012379451344246c5156d29938f12886Alice Yang                getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
522a990a715012379451344246c5156d29938f12886Alice Yang                return;
523a990a715012379451344246c5156d29938f12886Alice Yang            }
524e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
525e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
5260aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
527a990a715012379451344246c5156d29938f12886Alice Yang                mShowQuotedText = true;
528e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
5298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
5308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
531bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
532a990a715012379451344246c5156d29938f12886Alice Yang
533a990a715012379451344246c5156d29938f12886Alice Yang        mComposeMode = action;
5349f855d667e34fbf0d330845225c26956e540b819Andy Huang        finishSetup(action, intent, savedState);
53596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
536bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
537b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
538faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
539faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
540b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
541b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
542faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
543b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
544b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
545b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
54626d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
547b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
548faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
549dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
550b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
551b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
552b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
553b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
554b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
555b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
556b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
557b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
558b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
559b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
560faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
561b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
562b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
563b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
564b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
56547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
56647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
56747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
56847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
56947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
57047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
57147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
5727ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
5737ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
5747ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
5757ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
5767ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
5777ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
57847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
5795ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
5805ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
5815ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
58247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
58347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
5840617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
5850617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
5860617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
5870617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
5880617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
58947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
59047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
59147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
59247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
593b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
59447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
59547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
59647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
597b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
59847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
59947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
60047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
60147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
60247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
60347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
60447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
605b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
60647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
60747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
60847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
60947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
610b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
611b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
612b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
61347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
61447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
61547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
61647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
61747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
618a990a715012379451344246c5156d29938f12886Alice Yang    private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
61934a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
620f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
621f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
622f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
623f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
624f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
625a990a715012379451344246c5156d29938f12886Alice Yang        initActionBar();
626e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
627e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
628d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
629d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
630d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
631d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
632d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
633d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
634d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
63575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
636326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
637a990a715012379451344246c5156d29938f12886Alice Yang        updateHideOrShowQuotedText(mShowQuotedText);
6381623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
6399f855d667e34fbf0d330845225c26956e540b819Andy Huang        mRespondedInline = mInnerSavedState != null ?
6409f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
6411623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
6421623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
6431623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
64471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
64571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
646ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) {
647f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
648f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
649f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
65071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
65171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
65240882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
653433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
654433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
655433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
656433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
657433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
658433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
659433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
660433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
661433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
662433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
663433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
664433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
665433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
666433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
667433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
668433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
669433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
670433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
671433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
672433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
6732708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
6742708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
6752708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
6762708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
677ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                //$FALL-THROUGH$
678433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
679433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
680433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
681433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
682433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
683433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
684433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
685433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
686433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
687433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
688433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
689433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
690433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
691433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
692433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
693433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
694433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
695433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
696433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
697433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
6988743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
699433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
700433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
701433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
7021a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
7031a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
7041a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
7051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
7061a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
7071a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
7081a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
709818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
710c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromSpinner.initialize(mComposeMode, mAccount, mAccounts, mRefMessage);
711818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
7121a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
7131a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
714eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
715eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
716eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
717eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
718a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
7193d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
7203d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
721a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
722a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
723eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
724eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
725eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
726eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
727b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
728eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
729b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
730b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
731a990a715012379451344246c5156d29938f12886Alice Yang            // We were waiting for the user to create an account
732b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
733b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
734b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
735b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
736b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
737b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
738b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
739b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
740eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
741eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
742eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
743eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
744d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected final void onRestoreInstanceState(Bundle savedInstanceState) {
7457bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        final boolean hasAccounts = mAccounts != null && mAccounts.length > 0;
7467bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7477bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            clearChangeListeners();
7487bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
749e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
7509f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (mInnerSavedState != null) {
7519f855d667e34fbf0d330845225c26956e540b819Andy Huang            if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
7529f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
7539f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
754e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
755e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
756e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
757e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
758e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
760e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
761e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
762e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7637bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7647bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            initChangeListeners();
7657bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
766e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
767e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
768e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
769d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected final void onSaveInstanceState(Bundle state) {
770eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
7719f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle inner = new Bundle();
7729f855d667e34fbf0d330845225c26956e540b819Andy Huang        saveState(inner);
7739f855d667e34fbf0d330845225c26956e540b819Andy Huang        state.putBundle(KEY_INNER_SAVED_STATE, inner);
7749f855d667e34fbf0d330845225c26956e540b819Andy Huang    }
7759f855d667e34fbf0d330845225c26956e540b819Andy Huang
7769f855d667e34fbf0d330845225c26956e540b819Andy Huang    private void saveState(Bundle state) {
777b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
778b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
779b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
780b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
781e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
782e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
783e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
784e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
785e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
786e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
787e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
789e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7906273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
7916273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
792151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
793d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
794d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
795d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
799e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
800e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
801e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
802e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
803eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
804e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
805e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
806e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
807e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
808e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
809e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
811e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
812e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
813e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
814e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
815e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
8161f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
817e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
818e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
819e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
8201f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
821e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
824e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
825bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        } else if (message.appendRefMessageContent) {
826bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // If we have no ref message but should be appending
827bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // ref message content, we have orphaned quoted text. Save it.
828bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            state.putCharSequence(EXTRA_QUOTED_TEXT, mQuotedTextView.getQuotedTextIfIncluded());
829e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
830326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
831326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
8321623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
833816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
83462066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
83562066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
836e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
837e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
838e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
839e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
840e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
841e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
842e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
843e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
848e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
849e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
850e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
851d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
852e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
853e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
854e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
855e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
8568960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8578960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8588960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
8598960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
860e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
861b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
862b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
863e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
864e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
865e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
866a990a715012379451344246c5156d29938f12886Alice Yang        message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
867e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
868e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
869e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
870e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
871e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
872e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
873e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
874e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
875e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
876e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
877e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
8788960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
8798960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
8801f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
881e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
8821f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
8831f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
884ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static String formatSenders(final String string) {
8853c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
8863c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
8873c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
8883c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
8893c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
8903c9115813343861a44133b805fb9f55512d20948Mindy Pereira
891818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
892818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
893bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
894bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
895bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
89623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
89723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
898b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
899b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
90023e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
901fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
902f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal            MailActivity.setNfcMessage(mAccount.name);
903fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
904818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
905818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
906e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
907e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
90862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
90962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
910c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook        mFromSpinner.initialize(action, mAccount, mAccounts, mRefMessage);
911c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook
9129a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
9139a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
9149a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
9159a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
9169a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
917c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook                final String accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
9189a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
9199a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
920e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
921e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
922e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
923e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
924e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
925e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
926e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
92762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
929238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
93062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
9319a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
93262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
9339a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
93462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
935a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
936a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
93762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
93862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
939c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
94062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
941a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
942a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
943c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
944a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
945a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
94646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
94746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
94962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
95062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
95162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
95262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
95362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
95462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
95562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
95662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
95762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
95862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
95962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
96062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
96162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
96262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
9649016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler     * Given an account and the message we're replying to,
96562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
9679016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler     * @param refMessage Message to analyze for account selection
96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
96962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
97062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
97162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
97262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
973326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
97462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
97562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
97689bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
97762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
97862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
97962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
9809016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            allRecipients.addAll(Arrays.asList(refMessage.getToAddressesUnescaped()));
9819016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            allRecipients.addAll(Arrays.asList(refMessage.getCcAddressesUnescaped()));
98262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
98362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
98462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
98562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
98662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
98762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
98862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
98962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
99062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
99162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
99262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
99362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
99662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
99862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
99962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
100062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
100162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
100262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
100362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
100462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
10051617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
10061617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
10071617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
10081617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
10091617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
10101617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
101162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
101262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
101362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
101462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
101562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
101662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
101762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
101862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
101962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1020ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) {
1021ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final ReplyFromAccount from : account.getReplyFroms()) {
102262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
102362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
102462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
102562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
1026cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
1027cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
102862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
102962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1030e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
10318960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
103262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
103362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
103462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
103562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
1036cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
103762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
103862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
103962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
104062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
104162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
104262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
104362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
104462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
104562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
104662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
104762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
104846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
1049b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
1050a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
10518e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
10528e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
10538e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
10548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
10557b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
105693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
1057cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
1058cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
1059cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
106093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
1061cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
1062cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
1063cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
1064818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
106541500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mTo.setTokenizer(new Rfc822Tokenizer());
1066818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
106741500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mCc.setTokenizer(new Rfc822Tokenizer());
1068818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
106941500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mBcc.setTokenizer(new Rfc822Tokenizer());
107082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
107182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
10726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
107362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
107446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
107546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
1076433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
10771a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
10782eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1079eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
10805a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1081326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1082326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
108362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
108462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
108562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
108662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
108762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
108862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
108962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
109062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
109162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1092e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1093e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1094e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1095e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1096e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1097e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1098e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1099e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1100e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1101e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1102cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1103cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1104cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1105cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1106cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1107cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1108cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1109cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1110cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1111cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
111275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
111375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
111475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
111575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
11161d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
11171d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
111875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
111975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1120cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1121cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1122cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1123cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1124cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1125cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1126cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1127cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1128cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1129cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1130cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1131cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
113275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1133818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
113475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
113575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1136a990a715012379451344246c5156d29938f12886Alice Yang    private void initActionBar() {
1137a990a715012379451344246c5156d29938f12886Alice Yang        LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
1138eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1139e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1140e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1141e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1142a990a715012379451344246c5156d29938f12886Alice Yang        if (mComposeMode == ComposeActivity.COMPOSE) {
1143eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1144eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1145326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1146eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1147326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1148326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1149326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1150eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1151eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1152a990a715012379451344246c5156d29938f12886Alice Yang            switch (mComposeMode) {
1153326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1154eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1155326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1156326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1157eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1158326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1159326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1160eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1161326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1162326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
11636349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1164fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1165fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1166fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
11676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
11686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
11690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
11700aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
11711ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
11721ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // Check if To: address and email body needs to be prefilled based on extras.
11731ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // This is used for reporting rendering feedback.
11741ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
11751ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            Intent intent = getIntent();
11761ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            if (intent.getExtras() != null) {
11771ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String toAddresses = intent.getStringExtra(EXTRA_TO);
11781ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (toAddresses != null) {
11791ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
11801ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11811ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String body = intent.getStringExtra(EXTRA_BODY);
11821ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (body != null) {
11831ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    setBody(body, false /* withSignature */);
11841ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11851ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            }
11861ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
11871ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
118896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
118996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
119096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
119196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
119229a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
119396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
119496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
119596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
119696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
119796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
119896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
11990aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
12008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
12018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
12028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
12038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
12048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1206e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
12078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
12088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
12096349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1210c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1211c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1212e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
12131f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1214bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1215bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1216bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1217bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1218bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
12199016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        final List<String> toAddresses = Arrays.asList(message.getToAddressesUnescaped());
1220bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
12219016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        addCcAddresses(Arrays.asList(message.getCcAddressesUnescaped()), toAddresses);
12229016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        addBccAddresses(Arrays.asList(message.getBccAddressesUnescaped()));
12232421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
12242421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
12252421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
12265c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
12272421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
12282421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1229cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1230002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1231bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1232002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1233bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1234752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1235002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1236752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1237752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1238752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1239c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1240c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1241752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1242752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1243752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
12441a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1245c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1246002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1247002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1248bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1249752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1250752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1251752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1252752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1253752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1254002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1255752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1256752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1257002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1258002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1259002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1260002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
12613971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1262bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1263bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1264bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
12678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
12808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
12828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12830b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
12848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
12858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1287dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
12888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
12898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
12948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
12968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
12988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
13008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
13028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
13048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
13078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
13088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
13098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
13128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
13138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
13148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1315dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
13168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1317dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
13188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1319dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
13208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
13218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
13228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
13238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
1324bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                } else if (EXTRA_QUOTED_TEXT.equals(extra)) {
1325bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                    initQuotedText(value, true /* shouldQuoteText */);
13268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
13278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
13318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
13328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
13338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
13348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
13358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1336bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1337bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // TODO - support EXTRA_HTML_TEXT
13388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1339e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1340e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
1341bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1344a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1345a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1346a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
1350a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
13517dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee            return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME);
1352a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1353a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1354a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1355a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1356a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1357a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1358a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1359a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
13608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
13637dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from
13647dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * changing '+' into ' '
13657dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     *
13667dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @param toReplace Input string
13677dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @return The string with all "+" characters replaced with "%2B"
13687dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     */
13693b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static String replacePlus(String toReplace) {
13707dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee        return toReplace.replace("+", "%2B");
13717dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    }
13727dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee
13737dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    /**
13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
13778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
13788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
13798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
13808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
13818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
13828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
13838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
13858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
13868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
13878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
13888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
13908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1391a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1392a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1393a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
13948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
13958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
13968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
13978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
13998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
14038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
14048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
14068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
14078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
14098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
14108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
14128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
14138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
14147dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)),
14157dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                        UTF8_ENCODING_NAME));
14168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
14178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
14188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
14198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
14238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
14248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
14257dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME),
14268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
14278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
14288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
14298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
14328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1433bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1434bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1435434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1436434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1437434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1438434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1439434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1440434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1441434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1442434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1443434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1444434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1445434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1446434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1447434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1448434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1449434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1450434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1451434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1452434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1453434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1454434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
14553cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1456434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
14573cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14583cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
14593cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
14603cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
14613cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
14623cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
14633cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1464434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1465434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1466434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1467434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
14683cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14693cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1470434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1471434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1472434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
14733cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
14743cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
14753cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1476eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1477eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1478f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
147903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
148003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
148103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
148203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1483f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1484f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1485f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1486f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1487f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1488f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1489f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1490f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1491f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14925c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1493f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1494f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1495434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1496f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1497f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1498f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1499f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
15009a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
15019a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
15029a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
15039a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
15049a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
15059a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
15069a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
15079a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
15089a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
15099a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
15109a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
15119a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
15129a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
15139a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
15149a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
15159a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
15169a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
15179a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
15189a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
15199a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
15209a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1521f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
15229a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1523f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1524f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
15259a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1526f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
15279a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1528f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1529f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1530f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1531f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1532f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1533f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1534f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1535f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1536f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1537f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1538bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private void initQuotedText(CharSequence quotedText, boolean shouldQuoteText) {
1539bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mQuotedTextView.setQuotedTextFromHtml(quotedText, shouldQuoteText);
1540bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mShowQuotedText = true;
1541bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
1542f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1543e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1544e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
15459932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
15469932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
154746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
154846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
154946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1550ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1551326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1552326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1553ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1554326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1555ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1556326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1557ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1558ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1559cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1560ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1561ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
156246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
156346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1564a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1565326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1566326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1567326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1568326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1569326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1570326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1571326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1572326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1573326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1574013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1575013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1576013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1577013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1578013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
15792421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
15802421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
15812421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
15825c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
15835c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
15842421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
15852421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1586013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
15875c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
15885c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
15895c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1590434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1591434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1592434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1593434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
15945c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
15955c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
15965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
15975c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
15985c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1599434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
16009932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
16019932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
16029932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1603013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
16049932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
16059932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1606434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1607013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1608013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1609013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
16100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
16114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
16124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
16134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
16144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
1615ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        initReplyRecipients(refMessage, action);
16164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16186d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // TODO: This should be private.  This method shouldn't be used by ComposeActivityTests, as
16196d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // it doesn't setup the state of the activity correctly
1620818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
1621ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    void initReplyRecipients(final Message refMessage, final int action) {
16229016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        String[] sentToAddresses = refMessage.getToAddressesUnescaped();
1623a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
162489de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String[] replyToAddresses = refMessage.getReplyToAddressesUnescaped();
162589de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        String replyToAddress = replyToAddresses.length > 0 ? replyToAddresses[0] : null;
162689de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String[] fromAddresses = refMessage.getFromAddressesUnescaped();
162789de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String fromAddress = fromAddresses.length > 0 ? fromAddresses[0] : null;
162889de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler
162965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
163089de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        if (TextUtils.isEmpty(replyToAddress)) {
163189de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            replyToAddress = fromAddress;
163265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
16334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
16354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
16364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1637a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1638a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
163989de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses);
1640a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1641a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
16424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
164389de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses);
1644154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
1645ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, sentToAddresses);
16469016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            addRecipients(ccAddresses, refMessage.getCcAddressesUnescaped());
16474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
16484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
16524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
16534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
16568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
16578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
16584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1660bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1661bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1662bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1663bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
16644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
16654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
16664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
16674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
16684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
16708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
16744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
16754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
16778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
16788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
16828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
16838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
16848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
16858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
16868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
16878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
16884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1691ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) {
1692ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final HashSet<String> hash = new HashSet<String>();
1693ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final Rfc822Token[] tokens : list) {
16944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
16954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
16964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
16994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
17024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
17034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
17044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
17064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
17074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
17094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
17124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
17134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
17144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
17154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1718ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static void addAddressToList(final String address, final RecipientEditTextView list) {
17194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
17204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
17214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1722ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
17234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
17254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
17264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
1730ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    protected Collection<String> initToRecipients(final String fullSenderAddress,
1731ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            final String replyToAddress, final String[] inToAddresses) {
17324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
17334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
17344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
17354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
17364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
17374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
173865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
17393ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
17404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
174165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
174265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
174365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
174465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
174565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
174665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
174765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
174865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
174965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
175065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
175165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
175265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
175365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
175465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
175565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1756fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
17571469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
17584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
17604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1762ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void addRecipients(final Set<String> recipients, final String[] addresses) {
1763ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : addresses) {
1764cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1765cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
17664a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
17675ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
17684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
17694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
177146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
177246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1773cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1774cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1775cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1776cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1777cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1778cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1779cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
17805ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
17815ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1782fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1783cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1784cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
1785bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
1786bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Returns a formatted subject string with the appropriate prefix for the action type.
1787bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * E.g., "FWD: " is prepended if action is {@link ComposeActivity#FORWARD}.
1788bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
1789bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static String buildFormattedSubject(Resources res, String subject, int action) {
179046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
179146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
179246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
179346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
179446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
1795bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            prefix = res.getString(R.string.forward_subject_label);
179646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
1797bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            prefix = res.getString(R.string.reply_subject_label);
179846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
179946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
180046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1801c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1802c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
180346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
180446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
1805bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            correctedSubject = String.format(
1806bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                    res.getString(R.string.formatted_subject), prefix, subject);
180746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
1808bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1809bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        return correctedSubject;
1810bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
1811bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1812bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private void setSubject(Message refMessage, int action) {
1813bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mSubject.setText(buildFormattedSubject(getResources(), refMessage.subject, action));
181446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
181546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1816818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1817818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1818818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1819818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1820eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1821eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1822818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1823679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
182482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1825679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
182633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
182733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1828c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
182933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1830c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
183182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1832c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
183382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
18348e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
18358e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
18368e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
18378e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
18382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        final int id = v.getId();
18392b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.add_cc_bcc) {
18402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Verify that cc/ bcc aren't showing.
18412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Animate in cc/bcc.
18422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            showCcBccViews();
18432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_photo_attachment) {
18442b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_PHOTO);
18452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_video_attachment) {
18462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_VIDEO);
18478e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
18488e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1849b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1850b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1851b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1852b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1853b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1854b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1855b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1856b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1857b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1858b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
18591d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
18601d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
18611d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
18621d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
18631d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
18641d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
18651d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
18661d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
18671d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
18681d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18691d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
18701d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
18711d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
18721d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18731d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
18741d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
18761d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
18779f855d667e34fbf0d330845225c26956e540b819Andy Huang        enableSave(mInnerSavedState != null ?
18789f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
18791d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
18801d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
18811d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
18821d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
18831d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
18853ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
18863ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
18873ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
18883ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
18893ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
18903ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
18913ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
18923ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
18933ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
18943ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1895b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1896b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1897b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1898b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1899ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1900ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1901818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1902ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1903ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1904ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1905ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1906ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1907ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1908ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1909ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1910ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1911ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1912ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1913ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1914ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1915ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1916ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1917b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
19182b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        final int id = item.getItemId();
191975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
19202b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.add_photo_attachment) {
19212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_PHOTO);
19222b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_video_attachment) {
19232b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_VIDEO);
19242b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_cc_bcc) {
19252b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            showCcBccViews();
19262b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.save) {
19272b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doSave(true);
19282b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.send) {
19292b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doSend();
19302b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.discard) {
19312b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doDiscard();
19322b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.settings) {
19332b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.showSettings(this, mAccount);
19342b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == android.R.id.home) {
19352b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            onAppUpPressed();
19362b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.help_info_menu_item) {
19372b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
19382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.feedback_menu_item) {
19392b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.sendFeedback(this, mAccount, false);
19402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else {
19412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            handled = false;
1942b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1943b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1944b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1945326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1946b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1947b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1948b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1949b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1950b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1951b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1952b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1953b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1954b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1955b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
19561672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
19571672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
19581672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
1959daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1960daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1961daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1962daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1963daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1964daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1965daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1966daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1967daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1968daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1969daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
19700c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
1971daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1972daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1973daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1974daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1975daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1976daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
197733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
1978dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
197933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
198033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
198148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
1982dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
198348e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
198448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
1985e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1986e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
198782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
19887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
19897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
199082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
199182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
199282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1993e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1994e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
199582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
199682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1997e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1998e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1999e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
200044a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
200182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
200282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
200344a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
200482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
200582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
200682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
200744a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
200882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
200982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
201082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
201182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
20127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
201382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
201492551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
20157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
20167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
201782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
201882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
201982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
202044a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
202144a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
202282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
202382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
202482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
202582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
2026febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
2027febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
2028febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
2029febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
2030cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
2031cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
2032eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
203382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
203482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
203582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
203682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
203782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
203882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
2039ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount);
204072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
204172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
20429f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
204372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
20449f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
204572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
20469f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
204772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
204872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
204972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
205072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
205172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20529f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler        private static void incrementRecipientsTimesContacted(final Context context,
20539f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                final String addressString) {
20549f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            if (TextUtils.isEmpty(addressString)) {
20559f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                return;
20569f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            }
20579f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressString);
20589f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final ArrayList<String> recipients = new ArrayList<String>(tokens.length);
20599f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            for (int i = 0; i < tokens.length;i++) {
20609f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                recipients.add(tokens[i].getAddress());
20619f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            }
20629f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final DataUsageStatUpdater statsUpdater = new DataUsageStatUpdater(context);
20639f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            statsUpdater.updateWithAddress(recipients);
20649f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler        }
20659f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler
206672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
206772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
206872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2069ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private void sendOrSaveMessage(final long messageIdToSave,
2070ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) {
207172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
207272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
207372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
207472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
207572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
207672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
207772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20783c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
20793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
20803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
20813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2082013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
20833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
208472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
2085013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
20863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
20873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
20883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
20893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
20903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
20913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
20923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
20933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
20943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
20953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
20963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
20973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
20983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
20993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
21003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
21013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
21023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
21033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
21043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
21053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
21063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
21073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
21083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
210972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
21103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
21113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
21123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
21133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
21153c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2116ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) {
21173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
21183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
21193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
2120ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                for (final String key : keys) {
21213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
21223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2123ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
21243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
21253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
21263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2127ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
21287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
21297ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
213172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
213372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
2134bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein         * Use the {@link ContentResolver#call} method to send or save the message.
213572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
213672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
213772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2138ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle callAccountSendSaveMethod(final ContentResolver resolver,
2139ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final Account account, final String method,
2140ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage) {
214172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
214272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
214372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
214472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
214572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
214672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
214772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
214872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
214972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
215072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
215172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
215272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
215372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
215472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
215572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
215672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
215772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
215872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
215972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
216082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
216172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
21623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
21633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
21643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
21653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
21663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
21673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
216972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
217082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
217182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
217282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2173e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2174e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
217592551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
217682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
21773ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2178e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2179e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
218082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
21813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
218282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
21843c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
218582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
218682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
218782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
218882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
218982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
21903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
219282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
219382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
21973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
21993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
22003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
22013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
22033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
22043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
22053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
22063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
2207ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle initializeAttachmentFds(final Context context,
2208ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final List<Attachment> attachments) {
22093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
22103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
22113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
22143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
22153c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22163c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
22173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
22183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
22193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
22203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
22223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
22233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
22243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
22253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
22263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2227c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2228c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2229c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2230c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2231c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2232c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2233c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2234c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2235c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2236c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2237c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2238c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2239c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
22403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
22413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
22433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
22443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
22453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
22483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
225482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
225582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
225682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
225782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
225882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
225982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
226082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
226182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
226282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
226382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
226482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
226582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
226682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
226782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
226982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
227082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
227182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
227282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
227382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
227482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
227582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
227682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
227782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
227882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
227982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
228082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
228182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
228282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
228382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
228482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
228582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
228682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
228782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
228882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
228982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2290ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) {
2291e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2292e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2293e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
2294ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : to) {
229582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
229682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
229882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
229982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
23012558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class RecipientErrorDialogFragment extends DialogFragment {
23022558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static RecipientErrorDialogFragment newInstance(final String message) {
23032558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final RecipientErrorDialogFragment frag = new RecipientErrorDialogFragment();
23042558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(1);
23052558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putString("message", message);
23062558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
23072558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
23082558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
23092558b509117872e539a6eaeb72aa63425529d50bTony Mantler
23102558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
23112558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
23122558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final String message = getArguments().getString("message");
23132558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity()).setMessage(message).setTitle(
23142558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    R.string.recipient_error_dialog_title)
23152558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
23162558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(
23172558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            R.string.ok, new Dialog.OnClickListener() {
23182558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        @Override
23192558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        public void onClick(DialogInterface dialog, int which) {
23202558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            ((ComposeActivity)getActivity()).finishRecipientErrorDialog();
23212558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        }
23222558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    }).create();
23232558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
23242558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
23252558b509117872e539a6eaeb72aa63425529d50bTony Mantler
23262558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishRecipientErrorDialog() {
23272558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // after the user dismisses the recipient error
23282558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // dialog we want to make sure to refocus the
23292558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // recipient to field so they can fix the issue
23302558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // easily
23312558b509117872e539a6eaeb72aa63425529d50bTony Mantler        if (mTo != null) {
23322558b509117872e539a6eaeb72aa63425529d50bTony Mantler            mTo.requestFocus();
23332558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
23342558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
23352558b509117872e539a6eaeb72aa63425529d50bTony Mantler
233682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
233782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
233882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
233982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
23402558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showRecipientErrorDialog(final String message) {
23412558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = RecipientErrorDialogFragment.newInstance(message);
23422558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "recipient error");
234382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
234482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
234582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
234682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
234782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
234882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2349eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
235082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
235182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
235282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
235382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
235482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
235582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
235682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
235782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
235882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
23597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
236082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
236182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
236282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
236382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2364a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2365d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2366a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
236782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
236882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
236982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
237082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2371bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
237282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
237382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
237482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
237582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2376bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2377bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2378bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2379bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2380bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2381bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2382bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2383bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2384bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2385bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2386bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2387bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2388bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2389bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2390bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2391bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2392bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2393bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2394bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2395bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2396bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2397bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2398bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2399bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2400bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2401bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2402bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2403bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2404bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2405bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
240682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
240782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
240882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
240982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
241082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
241182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
241282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
241382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2414eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
241582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
241633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
241733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
241882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2424dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2425009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2426009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2427dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2428dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2429dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2430009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2431009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2432009b3712ff1657fa839049826451321fdd938d32Mark Wei
2433ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final String[] to, cc, bcc;
2434181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2436181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2439181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2440181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2441181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2443181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2446181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2450181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2451181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2458181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2459181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2460181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2461181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2462181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2466181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2467181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
24682558b509117872e539a6eaeb72aa63425529d50bTony Mantler                boolean emptyBody = TextUtils.getTrimmedLength(mBodyView.getEditableText()) == 0;
2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2474181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2475181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2476181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2477181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2478181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
24792558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, save,
24802558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2481181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2482181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2483181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
24852558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, save,
24862558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
24922558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showSendConfirmDialog(R.string.confirm_send_message, save, showToast);
2493181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2494181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2495181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2496181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
24972558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
2498181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2499181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2500181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2501181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2502181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2503181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
25045c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2505181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2506181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2507181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2508181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2509181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2510181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2511181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2512181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2513181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2514181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2515181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2517181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
25202558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class SendConfirmDialogFragment extends DialogFragment {
25212558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static SendConfirmDialogFragment newInstance(final int messageId,
25222558b509117872e539a6eaeb72aa63425529d50bTony Mantler                final boolean save, final boolean showToast) {
25232558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final SendConfirmDialogFragment frag = new SendConfirmDialogFragment();
25242558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(3);
25252558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putInt("messageId", messageId);
25262558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("save", save);
25272558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("showToast", showToast);
25282558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
25292558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
2530181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
25312558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25322558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
25332558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
25342558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final int messageId = getArguments().getInt("messageId");
25352558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean save = getArguments().getBoolean("save");
25362558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast = getArguments().getBoolean("showToast");
25372558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25382558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
25392558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(messageId)
25402558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setTitle(R.string.confirm_send_title)
25412558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
25422558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.send,
25432558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
2544aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy                                @Override
25452558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int whichButton) {
25462558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).finishSendConfirmDialog(save,
25472558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                            showToast);
25482558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
25492558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
25502558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
25512558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
25522558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
25532558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25542558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishSendConfirmDialog(final boolean save, final boolean showToast) {
25552558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
25562558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
25572558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25582558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showSendConfirmDialog(final int messageId, final boolean save,
25592558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast) {
25602558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = SendConfirmDialogFragment.newInstance(messageId, save,
25612558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showToast);
25622558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "send confirm");
2563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2567181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2576181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2578181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2579181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2580181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2586e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
258705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
258844a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
258944a6339dd80f4b5b9e5d54567021698d92467c5emindyp            ReplyFromAccount draftAccount) {
2590b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
259129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2592b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2593c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2594e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2595e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2596e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
259729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
25988960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
259992551d057965689f1952faeb06763f0762bc717fMindy Pereira
2600e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2601b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2602b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
260305b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
260429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
260529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
260629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2607e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2608e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2609e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2610e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
261155271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
261255271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
261355271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
261412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2615e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
261629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2617e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2618e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2619e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2620e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
262129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
262229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2623002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
262412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2625c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2626c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2627c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2628c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2629c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2630c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2631c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2632c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2633c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2634c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2635c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2636c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2637c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2638e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
263912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
264012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
264112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
26423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
26433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
264444a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
264544a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
264682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2647181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2648181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2649181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2650181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
265182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2652181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2653181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
265482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2655b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2656b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2657b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2658b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2659b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2660b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2661b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2662b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2663b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2664b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2665002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2666002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2667002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2668002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2669002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2670002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2671002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2672002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2673002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2674002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2675002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2676002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2677002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2678002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2679002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2680002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2681002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2682002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2683002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
26842558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void sendOrSave(final boolean save, final boolean showToast) {
2685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
26873ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
269082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26912558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final Spanned body = mBodyView.getEditableText();
26922558b509117872e539a6eaeb72aa63425529d50bTony Mantler
2693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
26941f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
269582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
269682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26970bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
269882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
271382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27140bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
27157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
27167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2717181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
271844a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
27217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
27227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
27237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
27287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2730181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
273182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27320bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
27337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
27347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
27357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
27367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
27377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
273882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27390bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
27407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
274147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
274247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
274347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
274447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
27457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
27467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
27477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
27487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
27497ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
27507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
27517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
27527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
27537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
27547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
275582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
27577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
27587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
27597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
27607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
27617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
276282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
27647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
27657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
27667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
27677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
27687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
27697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
27707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2771181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
27731e05a1eedd720aac611c6402c3655ec92c23a43bTony Mantler        setAccount(mReplyFromAccount.account);
2774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2775181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2776181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2777181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2778181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2779181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2780181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2781181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2782e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
278305b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
278405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
278544a6339dd80f4b5b9e5d54567021698d92467c5emindyp                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount);
2786181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2787181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2788181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2789181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2790181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2791181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2792181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2793181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2794181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2795181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2796181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2797181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2798181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2799181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2800181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2801181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2802181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2803181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2804181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2805181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2806181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2807181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2808181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2810181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2811181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2812181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2813181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
281482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28152db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2816013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2817013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2818d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
28192db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2820013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2821181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2822181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2823013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2824013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2825ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2826a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2827ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2828cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2829ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2830ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2831ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2832326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2833326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2834a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2835326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2836326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2837326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2838326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2839326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2840326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2841326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2842cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2843a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2844154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
284568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
28460aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
28478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2848ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2849ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2850ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2851ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2852ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
28538960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2854ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2855ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
28568960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
28578960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
285868c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
285968c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
28609b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
286168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2862ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2863ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2864a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2865ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2866cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2867326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2868326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2869326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2870b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2871b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2872154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2873154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2874154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2875154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2876154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2877154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2878154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2879154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2880154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2881154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2882154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2883154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2884154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2885154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2886154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2887154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2888154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2889154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2890154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2891154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2892154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2893154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2894326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2895326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2896326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2897326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2898326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2899326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2900326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2901326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2902326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2903326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2904326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2905326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2906326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2907326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2908326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2909326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2910326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2911326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2912326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2913326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2914326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2915326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2916326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2917326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2918326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
291946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
292046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
292146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
292246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
292340882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
29241623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
292509dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
29268654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
292709dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
292846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
292946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
293046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
293146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
293246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
293346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
293446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
293546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
293646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
293746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2938eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
293946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
294046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
294146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
294246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
294346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
294446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
294546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
294646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
294746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2948bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
294946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
295046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
295146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
295246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2953eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2954bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2955bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2956bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2957bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2958bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2959bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2960b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2961433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
29622708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
29632708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
2964b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
29652708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
2966b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2967b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2968b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2969b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2970b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2971433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2972433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2973433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2974bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2975bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2976bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2977bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2978bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2979bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2980bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2981bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2982bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
298346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
29841a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
29855a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
29865a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
298792551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
298892551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2989f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
2990f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
2991f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
2992f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
2993f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
2994f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
2995f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
2996f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
2997f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
2998f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
2999b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
3000f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
3001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
3002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
3003181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
3004181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
3005181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
3006181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
3007181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
3008181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
300982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
30101a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
301182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
301282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
301382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
301482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
301582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
301682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
301782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
30182558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class DiscardConfirmDialogFragment extends DialogFragment {
30192558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
30202558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
30212558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
30222558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(R.string.confirm_discard_text)
30232558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.discard,
30242558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
30252558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                @Override
30262558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int which) {
30272558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).doDiscardWithoutConfirmation();
30282558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
30292558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
30302b215b7e4aa5901322dd6ef2e4e8616a4552e9b3Tony Mantler                    .setNegativeButton(R.string.cancel, null)
30312558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
303282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
303382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
303482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3035efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
30362558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = new DiscardConfirmDialogFragment();
30372558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "discard confirm");
3038efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
303982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
304082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
304182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
304282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
304382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
304482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
30452558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void doDiscardWithoutConfirmation() {
30467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
304782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
304882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
3049b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
305078ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
3051cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
3052cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
30530bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
3054cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
305582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
305682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
305782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
305882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
305982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
306082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
306182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
306282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
30632558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // Display a toast to let the user know
30642558b509117872e539a6eaeb72aa63425529d50bTony Mantler        Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
306582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
306682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
306782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
306882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
306982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
307082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3071eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
3072eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
3073eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
3074eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
3075eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
3076eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
3077eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3078eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3079eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
308048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
3081eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3082eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
3083eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3084eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
3085eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
3086eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
308740882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
308840882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
308940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
3090eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
3091eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
309275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309340882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
309440882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
309540882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
309640882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
309740882430c874ff29890ec6fa31f7649788cbc470mindyp    }
309875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
310075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
310175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
31020bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
310375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
310475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
310575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
310675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
310775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
310875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
310975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
311075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
311175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
311275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
31130bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
311475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
311575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
311675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
311775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
311875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
311975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
312075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
312175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
312275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
312375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
312475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
312575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
312675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
312775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
312875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
312975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
313075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
313175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
313275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
313375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
313475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
313575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
313675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
313775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
313875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
313975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
314075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
314175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
314275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
314375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
314475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
314575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
314675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
314775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
314875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
314975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
315075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
315175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
315275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
315375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
315475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
315575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
315675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
315775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
315875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
315975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
316075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
316175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
316275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
316375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
316475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
316575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
316675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
316775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
316875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
316975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
317075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
317175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
317275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
317375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
317475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
317575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
317675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
317775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
317875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
317975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
318075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
318175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
318275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
318375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
318475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
318575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
318675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
318775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
318875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
318975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
319075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
319175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
319275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3193e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3194e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3195e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3196e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3197e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3198e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3199e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3200bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3201bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3202bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3203bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3204bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
320596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
320696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
320796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
320896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
3209a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3210a990a715012379451344246c5156d29938f12886Alice Yang                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
3211a990a715012379451344246c5156d29938f12886Alice Yang                        null, null);
321296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
321396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
321496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3215b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3216b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3217b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
321896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
321996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
322096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
322196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
322296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
322396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3224b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3225b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3226a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3227b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3228b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3229b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3230a990a715012379451344246c5156d29938f12886Alice Yang                    initFromRefMessage(mComposeMode);
3231a990a715012379451344246c5156d29938f12886Alice Yang                    finishSetup(mComposeMode, intent, null);
3232a990a715012379451344246c5156d29938f12886Alice Yang                    if (mComposeMode != FORWARD) {
3233b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3234b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
32350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
32360aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3237b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3238b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3239b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3240b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3241b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3242b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3243b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
324496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3245b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3246a990a715012379451344246c5156d29938f12886Alice Yang            case REFERENCE_MESSAGE_LOADER:
3247a990a715012379451344246c5156d29938f12886Alice Yang                // Only populate mRefMessage and leave other fields untouched.
3248a990a715012379451344246c5156d29938f12886Alice Yang                if (data != null && data.moveToFirst()) {
3249a990a715012379451344246c5156d29938f12886Alice Yang                    mRefMessage = new Message(data);
3250a990a715012379451344246c5156d29938f12886Alice Yang                }
32519f855d667e34fbf0d330845225c26956e540b819Andy Huang                finishSetup(mComposeMode, getIntent(), mInnerSavedState);
3252a990a715012379451344246c5156d29938f12886Alice Yang                break;
3253b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3254b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3255b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3256b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3257faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3258faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3259b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3260b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3261dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3262b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3263b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3264b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3265b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3266b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3267b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3268b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3269b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3270faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3271faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3272faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3273b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3274b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3275b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3276b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3277b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3278b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3279b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3280b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3281b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3282b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3283b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3284b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3285b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3286b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3287b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3288b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
328996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3290b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3291b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3292b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
329396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
329496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
329596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3296b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3297b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3298b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3299b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3300b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3301b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3302b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3303b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3304b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3305b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3306b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3307b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
330896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
330996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
331096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
331196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
331283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
331383e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
331483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
331583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
331683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
33171f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3318