ComposeActivity.java revision 59e69095bd558a1e6ae890ce79b7b848331d0cc6
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/**
28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc.
38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License.
68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at
78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software
118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and
148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License.
158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */
168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose;
188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener;
215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
252558b509117872e539a6eaeb72aa63425529d50bTony Mantlerimport android.app.DialogFragment;
26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment;
27b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction;
2896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager;
296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
3296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader;
3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader;
3682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
37bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sappersteinimport android.content.res.Resources;
387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor;
441ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable;
4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
48ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString;
4982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
50c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
5182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
5246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
53c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
543cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity;
5562d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent;
56326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
58b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
59b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
63b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection;
6462d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo;
65326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
67433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
69013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
707b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
71c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
729f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantlerimport com.android.common.contacts.DataUsageStatUpdater;
735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
745680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService;
755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
76761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huangimport com.android.mail.analytics.Analytics;
771ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView;
7840882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
799932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
805a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
8130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
8233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
8330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
8430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
855680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
873ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8992551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
90181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
9130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
923ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
9312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
941ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
96fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
97b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
99434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
100febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
101b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
10230e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
10330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
10446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
113bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
11446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1181c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
119bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
12082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
12146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
12246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1232558b509117872e539a6eaeb72aa63425529d50bTony Mantler        RespondInlineListener, TextWatcher,
124a990a715012379451344246c5156d29938f12886Alice Yang        AttachmentAddedOrDeletedListener, OnAccountChangedListener,
125a990a715012379451344246c5156d29938f12886Alice Yang        LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
126a990a715012379451344246c5156d29938f12886Alice Yang        FeedbackEnabledActivity {
1276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
128bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int COMPOSE = -1;
129bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int REPLY = 0;
130bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int REPLY_ALL = 1;
131bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int FORWARD = 2;
132bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static final int EDIT_DRAFT = 3;
1336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
13596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
137326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
138326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1391623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1401d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
141a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
150bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
151bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Expected to be html formatted text.
152bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
153bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private static final String EXTRA_QUOTED_TEXT = "quotedText";
154bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
155d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1569a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
15762066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
15862066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
16460847256c691b2677772a46919038f9c600fecf7Scott Kennedy    /**
16560847256c691b2677772a46919038f9c600fecf7Scott Kennedy     * An optional extra containing a {@link ContentValues} of values to be added to
16660847256c691b2677772a46919038f9c600fecf7Scott Kennedy     * {@link SendOrSaveMessage#mValues}.
16760847256c691b2677772a46919038f9c600fecf7Scott Kennedy     */
16860847256c691b2677772a46919038f9c600fecf7Scott Kennedy    public static final String EXTRA_VALUES = "extra-values";
16960847256c691b2677772a46919038f9c600fecf7Scott Kennedy
1708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
171bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC,
172bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            EXTRA_QUOTED_TEXT };
1738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
17482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
17582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
17682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
17782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
17882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
17982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
18182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
18282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
18382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
18482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
18582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1861f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
18782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
1886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
194daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
196e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
197f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1985680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    /** If set, we will clear notifications for this folder. */
1995680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder";
2005680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
2013ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
20236bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
203b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
204b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
205b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
206434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
207bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
208bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
2094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
210b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
211013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
212013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
213013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
2148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
215e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
2168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
217e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
218e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
219e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
220176a1993ab15298de58f0cc988939b2cc1632689Paul Westbrook    private static final String EXTRA_FOCUS_SELECTION_END = "focusSelectionEnd";
221e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
22296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
223b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
224a990a715012379451344246c5156d29938f12886Alice Yang    private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
22547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
226b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2272db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2282db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2298e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2309f855d667e34fbf0d330845225c26956e540b819Andy Huang    private static final String KEY_INNER_SAVED_STATE = "compose_state";
2319f855d667e34fbf0d330845225c26956e540b819Andy Huang
23282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
23382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
23482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
23582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
236c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
237c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
238c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2398e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2417b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
24233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
24359e69095bd558a1e6ae890ce79b7b848331d0cc6Tony Mantler    protected ReplyFromAccount mReplyFromAccount;
244181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
24582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
248326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
249326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
25046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
25146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
25259e69095bd558a1e6ae890ce79b7b848331d0cc6Tony Mantler    protected EditText mBodyView;
2531a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2542eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
255eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2561883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2571883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
258013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
259eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
26082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
26182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
26282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
26382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
264b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
265b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
26844a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
27093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
27193b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2723ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
273326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
274daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
275daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
276daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
277cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
278cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
279cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
280b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
281a990a715012379451344246c5156d29938f12886Alice Yang    private boolean mShowQuotedText = false;
2829f855d667e34fbf0d330845225c26956e540b819Andy Huang    private Bundle mInnerSavedState;
28360847256c691b2677772a46919038f9c600fecf7Scott Kennedy    private ContentValues mExtraValues = null;
284daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2851623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2861623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2871623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2881623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2891623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2901623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2911623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2921623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2931623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2941623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
295dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang    private boolean mPerformedSendOrDiscard = false;
2961623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
297daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
298326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
299326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
3003ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
30160847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, EDIT_DRAFT, null, null, null, null,
30260847256c691b2677772a46919038f9c600fecf7Scott Kennedy                null /* extraValues */);
303326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
304326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
3056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
30833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
30960847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, null, COMPOSE, null, null, null, null, null /* extraValues */);
3106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3126349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3136349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3146349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3153de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    public static void composeToAddress(Context launcher, Account account, String toAddress) {
31660847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, null, COMPOSE, toAddress, null, null, null,
31760847256c691b2677772a46919038f9c600fecf7Scott Kennedy                null /* extraValues */);
318bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
319bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
320bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
321bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Can be called from a non-UI thread.
322bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
323bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static void composeWithQuotedText(Context launcher, Account account,
32460847256c691b2677772a46919038f9c600fecf7Scott Kennedy            String quotedText, String subject, final ContentValues extraValues) {
32560847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, null, COMPOSE, null, null, quotedText, subject, extraValues);
3263de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    }
3273de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein
3283de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein    /**
3293de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     * Can be called from a non-UI thread.
3303de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein     */
3310aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
3320aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
3330aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
3340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3360aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3370aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3380aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3390aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3410aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3420aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3430aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3440aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3450aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3460aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3470aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3486d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        updateActionIntent(account, messageUri, action, intent);
3496d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3506d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook        return intent;
3516d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    }
3526d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook
3536d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    @VisibleForTesting
3546d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    static Intent updateActionIntent(Account account, Uri messageUri, int action, Intent intent) {
3550aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3560aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3570aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3580aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3590aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3600aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3610aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3620aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3630aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3640aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3650aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3663ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
36760847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, REPLY, null, null, null, null, null /* extraValues */);
3686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3733ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
37460847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, REPLY_ALL, null, null, null, null,
37560847256c691b2677772a46919038f9c600fecf7Scott Kennedy                null /* extraValues */);
3766349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3813ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
38260847256c691b2677772a46919038f9c600fecf7Scott Kennedy        launch(launcher, account, message, FORWARD, null, null, null, null, null /* extraValues */);
3836349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3851ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    public static void reportRenderingFeedback(Context launcher, Account account, Message message,
3861ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String body) {
387bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        launch(launcher, account, message, FORWARD,
38860847256c691b2677772a46919038f9c600fecf7Scott Kennedy                "android-gmail-readability@google.com", body, null, null, null /* extraValues */);
3891ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    }
3901ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
3911ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    private static void launch(Context launcher, Account account, Message message, int action,
39260847256c691b2677772a46919038f9c600fecf7Scott Kennedy            String toAddress, String body, String quotedText, String subject,
39360847256c691b2677772a46919038f9c600fecf7Scott Kennedy            final ContentValues extraValues) {
3946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
398bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
399bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
400bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
401bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
402bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
4031ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (toAddress != null) {
4041ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_TO, toAddress);
4051ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
4061ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (body != null) {
4071ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_BODY, body);
4081ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
409bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        if (quotedText != null) {
410bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            intent.putExtra(EXTRA_QUOTED_TEXT, quotedText);
411bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        }
412bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        if (subject != null) {
413bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            intent.putExtra(EXTRA_SUBJECT, subject);
414bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        }
41560847256c691b2677772a46919038f9c600fecf7Scott Kennedy        if (extraValues != null) {
41660847256c691b2677772a46919038f9c600fecf7Scott Kennedy            LogUtils.d(LOG_TAG, "Launching with extraValues: %s", extraValues.toString());
41760847256c691b2677772a46919038f9c600fecf7Scott Kennedy            intent.putExtra(EXTRA_VALUES, extraValues);
41860847256c691b2677772a46919038f9c600fecf7Scott Kennedy        }
4196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
4206349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
4218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
4228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
423d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected void onCreate(Bundle savedInstanceState) {
4248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
4258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
4269f855d667e34fbf0d330845225c26956e540b819Andy Huang        mInnerSavedState = (savedInstanceState != null) ?
4279f855d667e34fbf0d330845225c26956e540b819Andy Huang                savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null;
428b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
429b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
430b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
431b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
4329f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle savedState = mInnerSavedState;
43346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
434818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
435e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
43662066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
437a990a715012379451344246c5156d29938f12886Alice Yang        mShowQuotedText = false;
438bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        CharSequence quotedText = null;
439e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
44047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
44147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
4429f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (hadSavedInstanceStateMessage(savedState)) {
4439f855d667e34fbf0d330845225c26956e540b819Andy Huang            action = savedState.getInt(EXTRA_ACTION, COMPOSE);
4449f855d667e34fbf0d330845225c26956e540b819Andy Huang            account = savedState.getParcelable(Utils.EXTRA_ACCOUNT);
4459f855d667e34fbf0d330845225c26956e540b819Andy Huang            message = (Message) savedState.getParcelable(EXTRA_MESSAGE);
44662066e47fe69c33b60ed970e46809ba81d044064Mark Wei
4479f855d667e34fbf0d330845225c26956e540b819Andy Huang            previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
4489f855d667e34fbf0d330845225c26956e540b819Andy Huang            mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
449bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            quotedText = savedState.getCharSequence(EXTRA_QUOTED_TEXT);
450e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
45147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
452e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
453e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
454e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
45562066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
456e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
457b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
458e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
45962066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
46092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
46192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
462818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
463818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
464818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
465bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
466fe853d3427119202562519c2add6873590851705Scott Kennedy        initRecipients();
467fe853d3427119202562519c2add6873590851705Scott Kennedy
4685680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
4695680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
4705680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
4715680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4725680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4735680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
474d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
47548cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
47648cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder);
4775680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4785680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4795680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4805680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
481daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
482daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
483daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
484daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
485daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
486daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
487daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
488daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
489daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
490daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
491daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
49296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
493a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = true;
494a990a715012379451344246c5156d29938f12886Alice Yang            mComposeMode = action;
495a990a715012379451344246c5156d29938f12886Alice Yang            getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
49696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
49796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
498e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
5009f855d667e34fbf0d330845225c26956e540b819Andy Huang            showCcBcc(savedState);
501a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
502bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // if we should be showing quoted text but mRefMessage is null
503bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // and we have some quotedText, display that
504bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            if (mShowQuotedText && quotedText != null && mRefMessage == null) {
505bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                initQuotedText(quotedText, false /* shouldQuoteText */);
506bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            }
507e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
508e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
5098960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
5108960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
511ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
512bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
513bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
514bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
515bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
516bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
517bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
518bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
519bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
520bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
521bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
522bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
523bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
524bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
525bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
526bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
527bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
528a990a715012379451344246c5156d29938f12886Alice Yang            LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
529a990a715012379451344246c5156d29938f12886Alice Yang
530a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
531a990a715012379451344246c5156d29938f12886Alice Yang            if (message.refMessageUri != null) {
532a990a715012379451344246c5156d29938f12886Alice Yang                // If we're editing an existing draft that was in reference to an existing message,
533a990a715012379451344246c5156d29938f12886Alice Yang                // still need to load that original message since we might need to refer to the
534a990a715012379451344246c5156d29938f12886Alice Yang                // original sender and recipients if user switches "reply <-> reply-all".
535a990a715012379451344246c5156d29938f12886Alice Yang                mRefMessageUri = message.refMessageUri;
536a990a715012379451344246c5156d29938f12886Alice Yang                mComposeMode = action;
537a990a715012379451344246c5156d29938f12886Alice Yang                getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
538a990a715012379451344246c5156d29938f12886Alice Yang                return;
539a990a715012379451344246c5156d29938f12886Alice Yang            }
540e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
541e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
5420aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
543a990a715012379451344246c5156d29938f12886Alice Yang                mShowQuotedText = true;
544e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
5458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
5468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
547bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
548a990a715012379451344246c5156d29938f12886Alice Yang
549a990a715012379451344246c5156d29938f12886Alice Yang        mComposeMode = action;
5509f855d667e34fbf0d330845225c26956e540b819Andy Huang        finishSetup(action, intent, savedState);
55196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
552bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
553b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
554faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
555faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
556b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
557b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
558faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
559b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
560b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
561b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
56226d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
563b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
564faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
565dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
566b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
567b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
568b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
569b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
570b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
571b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
572b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
573b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
574b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
575b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
576faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
577b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
578b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
579b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
580b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
58147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
58247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
58347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
58447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
58547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
58647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
58747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
5887ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
5897ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
5907ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
5917ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
5927ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
5937ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
59447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
5955ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
5965ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
5975ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
59847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
59947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
6000617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
6010617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
6020617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
6030617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
6040617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
60547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
60647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
60747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
60847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
609b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
61047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
61147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
61247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
613b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
61447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
61547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
61647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
61747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
61847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
61947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
62047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
621b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
62247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
62347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
62447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
62547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
626b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
627b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
628b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
62947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
63047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
63147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
63247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
63347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
634a990a715012379451344246c5156d29938f12886Alice Yang    private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
63534a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
636f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
637f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
638f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
639f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
640f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
641a990a715012379451344246c5156d29938f12886Alice Yang        initActionBar();
642e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
643e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
644d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
645d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
646d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
647d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
648d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
649d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
650d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
65175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
652326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
653a990a715012379451344246c5156d29938f12886Alice Yang        updateHideOrShowQuotedText(mShowQuotedText);
6541623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
6559f855d667e34fbf0d330845225c26956e540b819Andy Huang        mRespondedInline = mInnerSavedState != null ?
6569f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
6571623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
6581623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
6591623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
66071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
66171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
662ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) {
663f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
664f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
665f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
66671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
66771c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
66840882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
669433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
670433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
671433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
672433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
673433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
674433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
675433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
676433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
677433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
678433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
679433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
680433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
681433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
682433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
683433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
684433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
685433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
686433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
687433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
688433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
6892708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
6902708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
6912708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
6922708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
693ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                //$FALL-THROUGH$
694433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
695433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
696433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
697433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
698433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
699433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
700433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
701433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
702433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
703433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
704433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
705433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
706433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
707433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
708433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
709433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
710433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
711433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
712433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
713433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
7148743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
715433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
716433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
717433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
7181a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
7191a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
7201a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
721761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    protected void onStart() {
722761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        super.onStart();
723761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
724761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        Analytics.getInstance().activityStart(this);
725761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    }
726761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
727761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    @Override
728761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    protected void onStop() {
729761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        super.onStop();
730761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
731761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang        Analytics.getInstance().activityStop(this);
732761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    }
733761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang
734761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang    @Override
7351a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
7361a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
7371a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
7381a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
739818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
740c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromSpinner.initialize(mComposeMode, mAccount, mAccounts, mRefMessage);
741818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
7421a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
7431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
744eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
745eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
746eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
747eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
748a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
7493d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
7503d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
751a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
752dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
753dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            if (isFinishing() && !mPerformedSendOrDiscard) {
754dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                // log saving upon backing out of activity. (we avoid logging every sendOrSave()
755dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                // because that method can be invoked many times in a single compose session.)
756dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                logSendOrSave(true /* save */);
757dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            }
758a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
759eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
760eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
761eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
762eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
763b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
764eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
765b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
766b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
767a990a715012379451344246c5156d29938f12886Alice Yang            // We were waiting for the user to create an account
768b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
769b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
770b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
771b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
772b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
773b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
774b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
775b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
776eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
777eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
778eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
779eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
780d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected final void onRestoreInstanceState(Bundle savedInstanceState) {
7817bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        final boolean hasAccounts = mAccounts != null && mAccounts.length > 0;
7827bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
7837bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            clearChangeListeners();
7847bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
785e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
7869f855d667e34fbf0d330845225c26956e540b819Andy Huang        if (mInnerSavedState != null) {
7879f855d667e34fbf0d330845225c26956e540b819Andy Huang            if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
7889f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START);
7899f855d667e34fbf0d330845225c26956e540b819Andy Huang                int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END);
790e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
791e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
792e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
793e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
794e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
795e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7997bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        if (hasAccounts) {
8007bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee            initChangeListeners();
8017bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee        }
802e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
803e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
804e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
805d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy    protected final void onSaveInstanceState(Bundle state) {
806eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
8079f855d667e34fbf0d330845225c26956e540b819Andy Huang        final Bundle inner = new Bundle();
8089f855d667e34fbf0d330845225c26956e540b819Andy Huang        saveState(inner);
8099f855d667e34fbf0d330845225c26956e540b819Andy Huang        state.putBundle(KEY_INNER_SAVED_STATE, inner);
8109f855d667e34fbf0d330845225c26956e540b819Andy Huang    }
8119f855d667e34fbf0d330845225c26956e540b819Andy Huang
8129f855d667e34fbf0d330845225c26956e540b819Andy Huang    private void saveState(Bundle state) {
813b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
814b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
815b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
816b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
820e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
821e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
824e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
825e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
8266273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
8276273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
828151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
829d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
830d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
831d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
832e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
833e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
834e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
835e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
836e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
837e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
838e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
839eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
840e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
841e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
842e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
843e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
848e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
849e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
850e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
851e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
8521f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
853e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
854e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
855e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
8561f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
857e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
858e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
859e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
860e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
861bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        } else if (message.appendRefMessageContent) {
862bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // If we have no ref message but should be appending
863bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // ref message content, we have orphaned quoted text. Save it.
864bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            state.putCharSequence(EXTRA_QUOTED_TEXT, mQuotedTextView.getQuotedTextIfIncluded());
865e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
866326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
867326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
8681623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
869816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
87062066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
87162066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
872e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
873e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
874e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
875e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
876e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
877e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
878e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
879e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
880e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
881e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
882e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
883e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
884e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
885e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
886e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
887d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
888e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
889e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
890e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
891e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
8928960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8938960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8948960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
8958960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
896e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
897b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
898b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
899e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
900e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
901e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
902a990a715012379451344246c5156d29938f12886Alice Yang        message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
903e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
904e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
905e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
906e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
907e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
908e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
909e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
910e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
911e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
912e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
913e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
9148960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
9158960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
9161f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
917e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
9181f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
9191f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
920ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static String formatSenders(final String string) {
9213c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
9223c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
9233c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
9243c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
9253c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
9263c9115813343861a44133b805fb9f55512d20948Mindy Pereira
927818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
928818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
929bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
930bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
931bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
93223e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
93323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
934b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
935b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
93623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
937fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
938f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal            MailActivity.setNfcMessage(mAccount.name);
939fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
940818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
941818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
942e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
943e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
94562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
946c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook        mFromSpinner.initialize(action, mAccount, mAccounts, mRefMessage);
947c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook
9489a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
9499a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
9509a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
9519a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
9529a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
953c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook                final String accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
9549a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
9559a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
956e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
957e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
958e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
959e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
960e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
961e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
962e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
96462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
965238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
9679a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
9699a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
97062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
971a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
972a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
97362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
97462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
975c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
97662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
977a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
978a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
979c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook            mFromStaticText.setText(mReplyFromAccount.name);
980a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
981a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
98246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
98346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
98462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
98562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
98662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
98762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
98862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
98962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
99062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
99162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
99262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
99362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
99662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
99862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
99962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
10009016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler     * Given an account and the message we're replying to,
100162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
100262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
10039016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler     * @param refMessage Message to analyze for account selection
100462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
100562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
100662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
100762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
100862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
1009326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
101062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
101162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
101289bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
101362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
101462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
101562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
10169016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            allRecipients.addAll(Arrays.asList(refMessage.getToAddressesUnescaped()));
10179016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            allRecipients.addAll(Arrays.asList(refMessage.getCcAddressesUnescaped()));
101862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
101962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
102062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
102162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
102262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
102362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
102462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
102562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
102662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
102762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
102862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
102962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
103062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
103162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
103262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
103362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
103462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
103562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
103662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
103762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
103862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
103962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
104062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
10411617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
10421617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
10431617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
10441617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
10451617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
10461617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
104762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
104862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
104962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
105062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
105162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
105262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
105362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
105462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
105562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1056ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) {
1057ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final ReplyFromAccount from : account.getReplyFroms()) {
105862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
105962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
106062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
106162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
1062cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
1063cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
106462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
106562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
1066e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
10678960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
106862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
106962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
107062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
107162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
1072cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
107362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
107462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
107562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
107662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
107762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
107862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
107962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
108062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
108162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
108262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
108362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
108446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
1085b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
1086a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
10878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
10888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
10898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
10908e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
10917b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
109293b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
1093cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
1094cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
1095cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
109693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
1097cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
1098cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
1099cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
1100818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
110141500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mTo.setTokenizer(new Rfc822Tokenizer());
1102818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
110341500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mCc.setTokenizer(new Rfc822Tokenizer());
1104818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
110541500399a7ee9066319c0b07055638b07312c8acScott Kennedy        mBcc.setTokenizer(new Rfc822Tokenizer());
110682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
110782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
11086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
110962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
111046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
111146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
1112433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
11131a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
11142eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1115eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
11165a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1117326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1118326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
111962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
112062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
112162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
112262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
112362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
112462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
112562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
112662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
112762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1128e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1129e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1130e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1131e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1132e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1133e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1134e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1135e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1136e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1137e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1138cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1139cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1140cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1141cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1142cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1143cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1144cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1145cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1146cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1147cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
114875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
114975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
115075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
115175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
11521d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
11531d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
115475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
115575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1156cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1157cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1158cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1159cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1160cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1161cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1162cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1163cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1164cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1165cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1166cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1167cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
116875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1169818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
117075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
117175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1172a990a715012379451344246c5156d29938f12886Alice Yang    private void initActionBar() {
1173a990a715012379451344246c5156d29938f12886Alice Yang        LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
1174eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1175e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1176e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1177e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1178a990a715012379451344246c5156d29938f12886Alice Yang        if (mComposeMode == ComposeActivity.COMPOSE) {
1179eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1180eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1181326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1182eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1183326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1184326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1185326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1186eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1187eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1188a990a715012379451344246c5156d29938f12886Alice Yang            switch (mComposeMode) {
1189326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1190eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1191326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1192326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1193eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1194326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1195326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1196eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1197326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1198326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
11996349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1200fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1201fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1202fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
12036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
12046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
12050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
12060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
12071ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
12081ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // Check if To: address and email body needs to be prefilled based on extras.
12091ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // This is used for reporting rendering feedback.
12101ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
12111ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            Intent intent = getIntent();
12121ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            if (intent.getExtras() != null) {
12131ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String toAddresses = intent.getStringExtra(EXTRA_TO);
12141ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (toAddresses != null) {
12151ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
12161ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
12171ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String body = intent.getStringExtra(EXTRA_BODY);
12181ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (body != null) {
12191ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    setBody(body, false /* withSignature */);
12201ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
12211ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            }
12221ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
12231ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
122496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
122596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
122696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
122796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
122829a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
122996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
123096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
123196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
123296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
123396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
123496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
12350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
12368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
12378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
12388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
12398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
12408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12410aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1242e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
12438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
12448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
12456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1246c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1247c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1248e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
12491f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1250bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1251bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1252bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1253bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1254bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
12559016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        final List<String> toAddresses = Arrays.asList(message.getToAddressesUnescaped());
1256bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
12579016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        addCcAddresses(Arrays.asList(message.getCcAddressesUnescaped()), toAddresses);
12589016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        addBccAddresses(Arrays.asList(message.getBccAddressesUnescaped()));
12592421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
12602421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
12612421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
12625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
12632421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
12642421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1265cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1266002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1267bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1268002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1269bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1270752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1271002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1272752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1273752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1274752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1275c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1276c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1277752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1278752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1279752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
12801a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1281c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1282002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1283002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1285752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1286752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1287752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1288752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1289752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1290002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1291752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1292752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1293002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1294002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1295002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1296002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
12973971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1299bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1300bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
13018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
13028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
13048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
13058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
13068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
13078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
13088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
13098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
13108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
13118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
13128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
13138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
13148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
13158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
13168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
13178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
13188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13190b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
13208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
13218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
13228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1323dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
13248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
13258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
13268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
13308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
13328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
13348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
13368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
13388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
13398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
13408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
13448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
134760847256c691b2677772a46919038f9c600fecf7Scott Kennedy        mExtraValues = intent.getParcelableExtra(EXTRA_VALUES);
134860847256c691b2677772a46919038f9c600fecf7Scott Kennedy        if (mExtraValues != null) {
134960847256c691b2677772a46919038f9c600fecf7Scott Kennedy            LogUtils.d(LOG_TAG, "Launched with extra values: %s", mExtraValues.toString());
135060847256c691b2677772a46919038f9c600fecf7Scott Kennedy        }
135160847256c691b2677772a46919038f9c600fecf7Scott Kennedy
13528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
13538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
13548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1356dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
13578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1358dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
13598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1360dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
1365bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                } else if (EXTRA_QUOTED_TEXT.equals(extra)) {
1366bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                    initQuotedText(value, true /* shouldQuoteText */);
13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1377bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1378bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            // TODO - support EXTRA_HTML_TEXT
13798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1380e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1381e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
1382bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
13838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1385a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1386a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1387a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
13888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
13908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
1391a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
13927dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee            return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME);
1393a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1394a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1395a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1396a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1397a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1398a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1399a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1400a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
14018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
14028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
14047dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from
14057dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * changing '+' into ' '
14067dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     *
14077dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @param toReplace Input string
14087dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @return The string with all "+" characters replaced with "%2B"
14097dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     */
14103b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static String replacePlus(String toReplace) {
14117dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee        return toReplace.replace("+", "%2B");
14127dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    }
14137dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee
14147dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    /**
14158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
14168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
14178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
14188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
14198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
14208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
14218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
14228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
14238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
14248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
14258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
14268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
14278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
14288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
14298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
14308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
14318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1432a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1433a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1434a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
14358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
14368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
14378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
14388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
14398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
14408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
14448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
14458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
14478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
14488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
14508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
14518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
14538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
14548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
14557dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)),
14567dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                        UTF8_ENCODING_NAME));
14578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
14588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
14598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
14608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
14638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
14648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
14658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
14667dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME),
14678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
14688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
14698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
14708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
14718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
14728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
14738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1474bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1475bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1476434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1477434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1478434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1479434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1480434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1481434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1482434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1483434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1484434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1485434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1486434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1487434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1488434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1489434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1490434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1491434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1492434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1493434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1494434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1495434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
14963cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1497434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
14983cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14993cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
15003cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
15013cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
15023cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
15033cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
15043cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1505434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1506434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1507434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1508434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
15093cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
15103cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1511434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1512434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1513434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
15143cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
15153cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
15163cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1517eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1518eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1519f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
152003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
152103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
152203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
152303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1524f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1525f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1526f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1527f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1528f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1529f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1530f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1531f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1532f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
15335c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1534f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1535f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1536434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1537f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1538f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1539f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1540f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
15419a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
15429a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
15439a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
15449a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
15459a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
15469a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
15479a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
15489a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
15499a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
15509a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
15519a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
15529a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
15539a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
15549a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
15559a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
15569a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
15579a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
15589a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
15599a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
15609a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
15619a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1562f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
15639a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1564f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1565f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
15669a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1567f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
15689a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1569f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1570f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1571f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1572f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1573f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1574f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1575f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1576f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1577f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1578f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1579bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private void initQuotedText(CharSequence quotedText, boolean shouldQuoteText) {
1580bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mQuotedTextView.setQuotedTextFromHtml(quotedText, shouldQuoteText);
1581bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mShowQuotedText = true;
1582bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
1583f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1584e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1585e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
15869932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
15879932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
158846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
158946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
159046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1591ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1592326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1593326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1594ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1595326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1596ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1597326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1598ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1599ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1600cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1601ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1602ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
160346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
160446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1605a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1606326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1607326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1608326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1609326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1610326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1611326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1612326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1613326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1614326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1615013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1616013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1617013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1618013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1619013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
16202421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
16212421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
16222421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
16235c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
16245c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
16252421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
16262421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1627013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
16285c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
16295c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
16305c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1631434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1632434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1633434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1634434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
16355c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
16365c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
16375c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
16385c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
16395c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1640434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
16419932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
16429932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
16439932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1644013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
16459932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
16469932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1647434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1648013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1649013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1650013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
16510aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
16524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
16534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
16544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
16554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
1656ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        initReplyRecipients(refMessage, action);
16574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16596d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // TODO: This should be private.  This method shouldn't be used by ComposeActivityTests, as
16606d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook    // it doesn't setup the state of the activity correctly
1661818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
1662ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    void initReplyRecipients(final Message refMessage, final int action) {
16639016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler        String[] sentToAddresses = refMessage.getToAddressesUnescaped();
1664a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
166589de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String[] replyToAddresses = refMessage.getReplyToAddressesUnescaped();
166689de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        String replyToAddress = replyToAddresses.length > 0 ? replyToAddresses[0] : null;
166789de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String[] fromAddresses = refMessage.getFromAddressesUnescaped();
166889de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        final String fromAddress = fromAddresses.length > 0 ? fromAddresses[0] : null;
166989de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler
167065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
167189de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler        if (TextUtils.isEmpty(replyToAddress)) {
167289de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            replyToAddress = fromAddress;
167365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
16744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
16764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
16774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1678a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1679a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
168089de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses);
1681a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1682a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
16834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
168489de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler            toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses);
1685154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
1686ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, sentToAddresses);
16879016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler            addRecipients(ccAddresses, refMessage.getCcAddressesUnescaped());
16884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
16894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
16934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
16944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
16978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
16988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
16994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1701bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1702bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1703bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1704bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
17054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
17064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
17074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
17084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
17094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
17118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
17128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
17138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
17144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
17154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
17164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
17188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
17198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
17208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
17218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
17228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
17238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
17248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
17258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
17268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
17278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
17288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
17294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1732ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) {
1733ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final HashSet<String> hash = new HashSet<String>();
1734ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final Rfc822Token[] tokens : list) {
17354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
17364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
17374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
17404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
17434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
17444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
17454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
17474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
17484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
17504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
17534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
17544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
17554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
17564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1759ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static void addAddressToList(final String address, final RecipientEditTextView list) {
17604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
17614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
17624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1763ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
17644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
17664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
17674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
17684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
17694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
17704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
1771ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    protected Collection<String> initToRecipients(final String fullSenderAddress,
1772ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            final String replyToAddress, final String[] inToAddresses) {
17734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
17744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
17754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
17764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
17774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
17784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
177965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
17803ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
17814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
178265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
178365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
178465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
178565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
178665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
178765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
178865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
178965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
179065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
179165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
179265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
179365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
179465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
179565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
179665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1797fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
17981469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
17994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
18004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
18014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
18024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1803ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void addRecipients(final Set<String> recipients, final String[] addresses) {
1804ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : addresses) {
1805cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1806cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
18074a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
18085ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
18094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
18104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
18114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
181246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
181346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1814cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1815cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1816cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1817cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1818cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1819cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1820cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
18215ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
18225ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1823fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1824cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1825cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
1826bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    /**
1827bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * Returns a formatted subject string with the appropriate prefix for the action type.
1828bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     * E.g., "FWD: " is prepended if action is {@link ComposeActivity#FORWARD}.
1829bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein     */
1830bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    public static String buildFormattedSubject(Resources res, String subject, int action) {
183146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
183246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
183346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
183446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
183546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
1836bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            prefix = res.getString(R.string.forward_subject_label);
183746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
1838bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            prefix = res.getString(R.string.reply_subject_label);
183946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
184046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
184146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1842c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1843c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
184446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
184546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
1846bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein            correctedSubject = String.format(
1847bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein                    res.getString(R.string.formatted_subject), prefix, subject);
184846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
1849bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1850bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        return correctedSubject;
1851bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    }
1852bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein
1853bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein    private void setSubject(Message refMessage, int action) {
1854bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein        mSubject.setText(buildFormattedSubject(getResources(), refMessage.subject, action));
185546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
185646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1857818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1858818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1859818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1860818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1861eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1862eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1863818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1864679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
186582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1866679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
186733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
186833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1869c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
187033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1871c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
187282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1873c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
187482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
18758e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
18768e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
18778e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
18788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
18792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        final int id = v.getId();
18802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.add_cc_bcc) {
18812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Verify that cc/ bcc aren't showing.
18822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Animate in cc/bcc.
18832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            showCcBccViews();
18842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_photo_attachment) {
18852b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_PHOTO);
18862b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_video_attachment) {
18872b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_VIDEO);
18888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
18898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1890b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1891b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1892b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1893b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1894b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1895b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1896b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1897b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1898b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1899b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
19001d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
19011d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
19021d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
19031d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
19041d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
19051d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
19061d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
19071d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
19081d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
19091d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
19101d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
19111d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
19121d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
19131d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
19141d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
19151d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
191682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
19171d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
19189f855d667e34fbf0d330845225c26956e540b819Andy Huang        enableSave(mInnerSavedState != null ?
19199f855d667e34fbf0d330845225c26956e540b819Andy Huang                mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED)
19201d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
19211d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
19221d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
19231d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
19241d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
192582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
19263ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
19273ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
19283ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
19293ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
19303ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
19313ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
19323ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
19333ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
19343ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
19353ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1936b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1937b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1938b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1939b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1940ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1941ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1942818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1943ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1944ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1945ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1946ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1947ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1948ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1949ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1950ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1951ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1952ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1953ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1954ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1955ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1956ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1957ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1958b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
19592b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        final int id = item.getItemId();
1960dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
1961dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        Analytics.getInstance().sendMenuItemEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, id, null, 0);
1962dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
196375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
19642b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.add_photo_attachment) {
19652b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_PHOTO);
19662b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_video_attachment) {
19672b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doAttach(MIME_TYPE_VIDEO);
19682b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.add_cc_bcc) {
19692b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            showCcBccViews();
19702b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.save) {
19712b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doSave(true);
19722b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.send) {
19732b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doSend();
19742b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.discard) {
19752b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            doDiscard();
19762b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.settings) {
19772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.showSettings(this, mAccount);
19782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == android.R.id.home) {
19792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            onAppUpPressed();
19802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.help_info_menu_item) {
19812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
19822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.feedback_menu_item) {
19832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            Utils.sendFeedback(this, mAccount, false);
19842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else {
19852b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            handled = false;
1986b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1987b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1988b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1989326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1990b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1991b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1992b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1993b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1994b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1995b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1996b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1997b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1998b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1999b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
20001672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
20011672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
20021672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
2003daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
2004daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
2005daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
2006daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
2007daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
2008daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
2009daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
2010daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2011daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
2012daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
2013daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
20140c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
2015daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
2016daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
2017daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
2018daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
2019daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
2020daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
202133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
2022dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
2023dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        logSendOrSave(false /* save */);
2024dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        mPerformedSendOrDiscard = true;
202533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
202633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
202748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
2028dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
202948e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
203048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
2031e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2032e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
203382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
20347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
20357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
203682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
203782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
203882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2039e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2040e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
204182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
204282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
2043e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
2044e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2045e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
204644a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
204782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
204882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
204944a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
205082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
205182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
205282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
205344a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
205482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
205582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
205682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
205782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
20587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
205982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
206092551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
20617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
20627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
206382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
206482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
206582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
206644a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
206744a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
206882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
206982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
207082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
207182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
2072febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
2073febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
2074febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
2075febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
2076cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
2077cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
2078eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
207982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
208082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
208182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
208282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
208382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
208482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
2085ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount);
208672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
208772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
20889f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
208972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
20909f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
209172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
20929f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                incrementRecipientsTimesContacted(mContext,
209372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
209472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
209572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
209672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
209772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20989f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler        private static void incrementRecipientsTimesContacted(final Context context,
20999f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                final String addressString) {
21009f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            if (TextUtils.isEmpty(addressString)) {
21019f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                return;
21029f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            }
21039f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressString);
21049f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final ArrayList<String> recipients = new ArrayList<String>(tokens.length);
21059f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            for (int i = 0; i < tokens.length;i++) {
21069f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler                recipients.add(tokens[i].getAddress());
21079f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            }
21089f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            final DataUsageStatUpdater statsUpdater = new DataUsageStatUpdater(context);
21099f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler            statsUpdater.updateWithAddress(recipients);
21109f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler        }
21119f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler
211272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
211372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
211472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2115ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private void sendOrSaveMessage(final long messageIdToSave,
2116ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) {
211772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
211872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
211972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
212072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
212172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
212272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
212372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
21243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
21253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
21263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
21273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2128013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
21293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
213072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
2131013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
21323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
21333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
21343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
21353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
21363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
21373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
21383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
21393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
21403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
21413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
21423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
21433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
21443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
21453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
21463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
21473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
21483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
21493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
21503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
21513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
21523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
21533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
21543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
215572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
21563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
21573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
21583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
21593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
21613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2162ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) {
21633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
21643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
21653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
2166ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                for (final String key : keys) {
21673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
21683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2169ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
21703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
21713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
21723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2173ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
21747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
21757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
217682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
217772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
217882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
217972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
2180bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein         * Use the {@link ContentResolver#call} method to send or save the message.
218172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
218272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
218372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2184ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle callAccountSendSaveMethod(final ContentResolver resolver,
2185ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final Account account, final String method,
2186ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage) {
218772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
218872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
218972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
219072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
219172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
219272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
219372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
219472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
219572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
219672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
219772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
219872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
219972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
220072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
220172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
220272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
220372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
220472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
220572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
220772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
22083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
22093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
22103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
22113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
22123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
22133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
221572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2219e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2220e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
222192551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
22233ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2224e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2225e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
22273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
22293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
22303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
223182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
223282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
223382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
223582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
22363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
223982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
224182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
224282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
22433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
22453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
22463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
22473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
22493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
22503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
22513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
22523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
2253ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle initializeAttachmentFds(final Context context,
2254ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final List<Attachment> attachments) {
22553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
22563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
22573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
22603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
22613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
22633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
22643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
22653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
22663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
22683c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
22693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
22703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
22713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
22723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2273c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2274c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2275c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2276c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2277c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2278c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2279c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2280c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2281c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2282c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2283c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2284c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2285c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
22863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
22873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
22893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
22903c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
22913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
22923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
22933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
22943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
229582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
229682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
229882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
229982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
230182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
230282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
230382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
230482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
230582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
230682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
230782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
230882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
230982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
231082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
231182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
231282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
231382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
231482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
231582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
231682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
231782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
231882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
231982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
232082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
232182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
232282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
232382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
232482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
232582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
232682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
232782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
232882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
232982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
233082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
233182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
233282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
233382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
233482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
233582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2336ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) {
2337e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2338e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2339e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
2340ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : to) {
234182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
234282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
234382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
234482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
234582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
234682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
23472558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class RecipientErrorDialogFragment extends DialogFragment {
2348f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        // Public no-args constructor needed for fragment re-instantiation
2349f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        public RecipientErrorDialogFragment() {}
2350f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook
23512558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static RecipientErrorDialogFragment newInstance(final String message) {
23522558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final RecipientErrorDialogFragment frag = new RecipientErrorDialogFragment();
23532558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(1);
23542558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putString("message", message);
23552558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
23562558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
23572558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
23582558b509117872e539a6eaeb72aa63425529d50bTony Mantler
23592558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
23602558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
23612558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final String message = getArguments().getString("message");
23622558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity()).setMessage(message).setTitle(
23632558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    R.string.recipient_error_dialog_title)
23642558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
23652558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(
23662558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            R.string.ok, new Dialog.OnClickListener() {
23672558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        @Override
23682558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        public void onClick(DialogInterface dialog, int which) {
23692558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            ((ComposeActivity)getActivity()).finishRecipientErrorDialog();
23702558b509117872e539a6eaeb72aa63425529d50bTony Mantler                        }
23712558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    }).create();
23722558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
23732558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
23742558b509117872e539a6eaeb72aa63425529d50bTony Mantler
23752558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishRecipientErrorDialog() {
23762558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // after the user dismisses the recipient error
23772558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // dialog we want to make sure to refocus the
23782558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // recipient to field so they can fix the issue
23792558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // easily
23802558b509117872e539a6eaeb72aa63425529d50bTony Mantler        if (mTo != null) {
23812558b509117872e539a6eaeb72aa63425529d50bTony Mantler            mTo.requestFocus();
23822558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
23832558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
23842558b509117872e539a6eaeb72aa63425529d50bTony Mantler
238582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
238682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
238782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
238882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
23892558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showRecipientErrorDialog(final String message) {
23902558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = RecipientErrorDialogFragment.newInstance(message);
23912558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "recipient error");
239282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
239382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
239482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
239582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
239682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
239782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2398eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
239982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
240082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
240182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
240282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
240382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
240482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
240582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
240682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
240782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
24087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
240982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
241082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
241182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
241282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2413a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2414d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2415a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
241682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
241782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
241882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
241982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2420bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
242182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
242282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
242382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
242482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2425bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2426bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2427bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2428bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2429bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2430bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2431bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2432bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2433bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2434bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2435bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2436bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2437bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2438bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2439bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2440bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2441bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2442bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2443bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2444bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2445bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2446bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2447bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2448bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2449bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2450bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2451bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2452bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2453bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2454bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
245582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
245682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
245782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
245882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
245982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
246082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
246182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
246282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2463eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
246482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
246533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
246633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
246782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2473dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2474009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2475009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2476dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2477dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2478dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2479009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2480009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2481009b3712ff1657fa839049826451321fdd938d32Mark Wei
2482ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final String[] to, cc, bcc;
2483181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2492181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2493181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2494181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2495181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2496181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2497181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2498181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2499181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2500181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2501181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2502181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2503181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2504181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2505181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2506181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2507181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2508181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2509181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2510181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2511181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2512181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2513181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2514181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2515181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
25172558b509117872e539a6eaeb72aa63425529d50bTony Mantler                boolean emptyBody = TextUtils.getTrimmedLength(mBodyView.getEditableText()) == 0;
2518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2520181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2525181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2526181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2527181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
25282558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, save,
25292558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2530181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2531181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2532181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2533181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
25342558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, save,
25352558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            showToast);
2536181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2540181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
25412558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showSendConfirmDialog(R.string.confirm_send_message, save, showToast);
2542181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2543181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2544181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2545181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
25462558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
2547181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2548181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2549181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2550181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2551181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
25535c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2556181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2559181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2567181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
25692558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class SendConfirmDialogFragment extends DialogFragment {
2570f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        // Public no-args constructor needed for fragment re-instantiation
2571f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        public SendConfirmDialogFragment() {}
2572f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook
25732558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public static SendConfirmDialogFragment newInstance(final int messageId,
25742558b509117872e539a6eaeb72aa63425529d50bTony Mantler                final boolean save, final boolean showToast) {
25752558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final SendConfirmDialogFragment frag = new SendConfirmDialogFragment();
25762558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final Bundle args = new Bundle(3);
25772558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putInt("messageId", messageId);
25782558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("save", save);
25792558b509117872e539a6eaeb72aa63425529d50bTony Mantler            args.putBoolean("showToast", showToast);
25802558b509117872e539a6eaeb72aa63425529d50bTony Mantler            frag.setArguments(args);
25812558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return frag;
2582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
25832558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25842558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
25852558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
25862558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final int messageId = getArguments().getInt("messageId");
25872558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean save = getArguments().getBoolean("save");
25882558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast = getArguments().getBoolean("showToast");
25892558b509117872e539a6eaeb72aa63425529d50bTony Mantler
25902558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
25912558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(messageId)
25922558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setTitle(R.string.confirm_send_title)
25932558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setIconAttribute(android.R.attr.alertDialogIcon)
25942558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.send,
25952558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
2596aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy                                @Override
25972558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int whichButton) {
25982558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).finishSendConfirmDialog(save,
25992558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                            showToast);
26002558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
26012558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
26022558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
26032558b509117872e539a6eaeb72aa63425529d50bTony Mantler        }
26042558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
26052558b509117872e539a6eaeb72aa63425529d50bTony Mantler
26062558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void finishSendConfirmDialog(final boolean save, final boolean showToast) {
26072558b509117872e539a6eaeb72aa63425529d50bTony Mantler        sendOrSave(save, showToast);
26082558b509117872e539a6eaeb72aa63425529d50bTony Mantler    }
26092558b509117872e539a6eaeb72aa63425529d50bTony Mantler
26102558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void showSendConfirmDialog(final int messageId, final boolean save,
26112558b509117872e539a6eaeb72aa63425529d50bTony Mantler            final boolean showToast) {
26122558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = SendConfirmDialogFragment.newInstance(messageId, save,
26132558b509117872e539a6eaeb72aa63425529d50bTony Mantler                showToast);
26142558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "send confirm");
2615181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2618181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2619181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2620181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2621181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2622181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2623181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2624181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2625181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2626181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2629181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2630181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2631181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2633181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2634181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2635181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2636181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2637181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2638e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
263905b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
264044a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
264160847256c691b2677772a46919038f9c600fecf7Scott Kennedy            ReplyFromAccount draftAccount, final ContentValues extraValues) {
2642b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
264329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2644b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2645c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2646e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2647e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2648e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
264929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
26508960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
265192551d057965689f1952faeb06763f0762bc717fMindy Pereira
2652e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2653b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2654b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
265505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
265629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
265729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
265829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2659e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2660e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2661e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2662e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
266355271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
266455271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
266555271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
266612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2667e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
266829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2669e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2670e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2671e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2672e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
267329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
267429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2675002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
267612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2677c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2678c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2679c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2680c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2681c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2682c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2683c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2684c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2685c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2686c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2687c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2688c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2689c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2690e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
269112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
269212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
269312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
269460847256c691b2677772a46919038f9c600fecf7Scott Kennedy        if (extraValues != null) {
269560847256c691b2677772a46919038f9c600fecf7Scott Kennedy            values.putAll(extraValues);
269660847256c691b2677772a46919038f9c600fecf7Scott Kennedy        }
26973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
26983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
269944a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
270044a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
270182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
270682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
270982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2710b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2711b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2712b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2713b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2714b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2715b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2716b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2717b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2718b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2719b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2720002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2721002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2722002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2723002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2724002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2725002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2726002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2727002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2728002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2729002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2730002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2731002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2732002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2733002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2734002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2735002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2736002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2737002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2738002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
27392558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void sendOrSave(final boolean save, final boolean showToast) {
2740181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2741181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
27423ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2743181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2744181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
274582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27462558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final Spanned body = mBodyView.getEditableText();
27472558b509117872e539a6eaeb72aa63425529d50bTony Mantler
2748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
27491f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
275082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
275182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27520bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
275382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2754181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2755181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2756181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2757181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2758181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2759181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2760181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2761181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2762181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2763181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2764181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2765181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2766181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2767181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
276882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27690bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
27707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
27717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
277344a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2775181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
27767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
27777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
27787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2779181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2780181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2781181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2782181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
27837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2784181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2785181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
278682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27870bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
27887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
27897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
27907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
27917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
27927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
279382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27940bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
27957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
279647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
279747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
279847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
279947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
28007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
28017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
28027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
28037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
28047ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
28057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
28067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
28077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
28087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
28097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
281082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
28127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
28137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
28147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
28157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
28167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
281782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
28197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
28207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
28217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
28227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
28237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
28247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
28257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2826181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2827181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
28281e05a1eedd720aac611c6402c3655ec92c23a43bTony Mantler        setAccount(mReplyFromAccount.account);
2829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2836181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2837e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
283805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
283905b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
284060847256c691b2677772a46919038f9c600fecf7Scott Kennedy                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount, mExtraValues);
2841181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2842181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2843181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2844181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2845181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2846181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2847181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2848181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2849181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2852181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2853181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2854181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2855181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2856181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2857181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2858181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2859181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2860181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2861181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2862181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2863181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2864181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2865181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2866181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2867181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2868181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
286982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
28702db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2871013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2872013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2873d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
28742db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2875013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2876181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2877181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2878013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2879013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2880ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2881a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2882ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2883cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2884ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2885ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2886ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2887dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang    private void logSendOrSave(boolean save) {
2888dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final String category = (save) ? "message_save" : "message_send";
2889dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final int attachmentCount = getAttachments().size();
2890dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final String msgType;
2891dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        switch (mComposeMode) {
2892dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case COMPOSE:
2893dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "new_message";
2894dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2895dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case REPLY:
2896dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "reply";
2897dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2898dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case REPLY_ALL:
2899dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "reply_all";
2900dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2901dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            case FORWARD:
2902dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "forward";
2903dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2904dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            default:
2905dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                msgType = "unknown";
2906dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang                break;
2907dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        }
2908dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final String label;
2909dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        final long value;
2910dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        if (mComposeMode == COMPOSE) {
2911dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            label = Integer.toString(attachmentCount);
2912dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            value = attachmentCount;
2913dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        } else {
2914dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            label = null;
2915dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang            value = 0;
2916dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        }
2917dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        Analytics.getInstance().sendEvent(category, msgType, label, value);
2918dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang    }
2919dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang
2920326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2921326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2922a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2923326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2924326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2925326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2926326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2927326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2928326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2929326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2930cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2931a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2932154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
293368c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
29340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
29358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2936ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2937ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2938ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2939ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2940ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
29418960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2942ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2943ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
29448960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
29458960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
294668c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
294768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
29489b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
294968c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2950ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2951ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2952a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2953ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2954cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2955326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2956326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2957326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2958b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2959b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2960154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2961154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2962154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2963154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2964154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2965154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2966154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2967154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2968154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2969154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2970154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2971154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2972154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2973154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2974154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2975154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2976154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2977154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2978154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2979154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2980154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2981154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2982326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2983326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2984326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2985326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2986326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2987326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2988326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2989326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2990326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2991326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2992326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2993326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2994326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2995326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2996326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2997326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2998326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2999326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
3000326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
3001326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
3002326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
3003326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
3004326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
3005326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
3006326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
300746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
300846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
300946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
301046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
301140882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
30121623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
301309dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
30148654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
301509dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
301646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
301746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
301846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
301946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
302046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
302146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
302246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
302346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
302446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
302546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
3026eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
302746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
302846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
302946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
303046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
303146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
303246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
303346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
303446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
303546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
3036bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
303746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
303846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
303946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
304046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
3041eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
3042bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
3043bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
3044bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
3045bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
3046bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
3047bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
3048b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
3049433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
30502708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
30512708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
3052b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
30532708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
3054b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
3055b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
3056b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
3057b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
3058b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
3059433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
3060433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
3061433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
3062bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
3063bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
3064bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
3065bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
3066bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
3067bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
3068bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
3069bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
3070bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
307146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
30721a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
30735a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
30745a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
307592551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
307692551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
3077f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
3078f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
3079f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
3080f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
3081f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
3082f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
3083f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
3084f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
3085f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
3086f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
3087b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
3088f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
3089181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
3090181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
3091181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
3092181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
3093181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
3094181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
3095181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
3096181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
309782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
30981a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
309982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
310082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
310182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
310282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
310382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
310482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
310582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
31062558b509117872e539a6eaeb72aa63425529d50bTony Mantler    public static class DiscardConfirmDialogFragment extends DialogFragment {
3107f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        // Public no-args constructor needed for fragment re-instantiation
3108f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook        public DiscardConfirmDialogFragment() {}
3109f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook
31102558b509117872e539a6eaeb72aa63425529d50bTony Mantler        @Override
31112558b509117872e539a6eaeb72aa63425529d50bTony Mantler        public Dialog onCreateDialog(Bundle savedInstanceState) {
31122558b509117872e539a6eaeb72aa63425529d50bTony Mantler            return new AlertDialog.Builder(getActivity())
31132558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setMessage(R.string.confirm_discard_text)
31142558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .setPositiveButton(R.string.discard,
31152558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            new DialogInterface.OnClickListener() {
31162558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                @Override
31172558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                public void onClick(DialogInterface dialog, int which) {
31182558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                    ((ComposeActivity)getActivity()).doDiscardWithoutConfirmation();
31192558b509117872e539a6eaeb72aa63425529d50bTony Mantler                                }
31202558b509117872e539a6eaeb72aa63425529d50bTony Mantler                            })
31212b215b7e4aa5901322dd6ef2e4e8616a4552e9b3Tony Mantler                    .setNegativeButton(R.string.cancel, null)
31222558b509117872e539a6eaeb72aa63425529d50bTony Mantler                    .create();
312382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
312482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
312582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3126efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
31272558b509117872e539a6eaeb72aa63425529d50bTony Mantler        final DialogFragment frag = new DiscardConfirmDialogFragment();
31282558b509117872e539a6eaeb72aa63425529d50bTony Mantler        frag.show(getFragmentManager(), "discard confirm");
3129efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
313082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
313182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
313282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
313382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
313482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
313582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
31362558b509117872e539a6eaeb72aa63425529d50bTony Mantler    private void doDiscardWithoutConfirmation() {
31377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
313882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
313982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
3140b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
314178ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
3142cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
3143cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
31440bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
3145cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
314682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
314782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
314882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
314982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
315082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
315182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
315282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
315382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
31542558b509117872e539a6eaeb72aa63425529d50bTony Mantler        // Display a toast to let the user know
31552558b509117872e539a6eaeb72aa63425529d50bTony Mantler        Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
315682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
315782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
315882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
3159dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang        mPerformedSendOrDiscard = true;
316082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
316182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
316282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
3163eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
3164eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
3165eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
3166eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
3167eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
3168eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
3169eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3170eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3171eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
317248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
3173eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
3174eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
3175eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
3176eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
3177eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
3178eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
317940882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
318040882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
318140882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
3182eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
3183eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
318475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
318540882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
318640882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
318740882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
318840882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
318940882430c874ff29890ec6fa31f7649788cbc470mindyp    }
319075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
319175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
319275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
319375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
31940bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
319575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
319675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
319775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
319875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
319975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
320075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
320175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
320275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
320375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
320475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
32050bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
320675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
320775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
320875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
320975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
321075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
321175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
321275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
321375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
321475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
321575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
321675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
321775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
321875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
321975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
322075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
322175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
322275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
322375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
322475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
322575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
322675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
322775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
322875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
322975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
323075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
323175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
323275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
323375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
323475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
323575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
323675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
323775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
323875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
323975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
324075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
324175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
324275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
324375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
324475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
324575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
324675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
324775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
324875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
324975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
325075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
325175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
325275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
325375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
325475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
325575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
325675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
325775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
325875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
325975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
326075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
326175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
326275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
326375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
326475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
326575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
326675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
326775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
326875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
326975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
327075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
327175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
327275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
327375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
327475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
327575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
327675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
327775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
327875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
327975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
328075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
328175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
328275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
328375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
328475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3285e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3286e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3287e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3288e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3289e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3290e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3291e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3292bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3293bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3294bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3295bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3296bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
329796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
329896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
329996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
330096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
3301a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3302a990a715012379451344246c5156d29938f12886Alice Yang                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
3303a990a715012379451344246c5156d29938f12886Alice Yang                        null, null);
330496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
330596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
330696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3307b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3308b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3309b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
331096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
331196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
331296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
331396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
331496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
331596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3316b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3317b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3318a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3319b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3320b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3321b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3322a990a715012379451344246c5156d29938f12886Alice Yang                    initFromRefMessage(mComposeMode);
3323a990a715012379451344246c5156d29938f12886Alice Yang                    finishSetup(mComposeMode, intent, null);
3324a990a715012379451344246c5156d29938f12886Alice Yang                    if (mComposeMode != FORWARD) {
3325b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3326b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
33270aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
33280aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3329b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3330b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3331b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3332b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3333b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3334b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3335b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
333696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3337b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3338a990a715012379451344246c5156d29938f12886Alice Yang            case REFERENCE_MESSAGE_LOADER:
3339a990a715012379451344246c5156d29938f12886Alice Yang                // Only populate mRefMessage and leave other fields untouched.
3340a990a715012379451344246c5156d29938f12886Alice Yang                if (data != null && data.moveToFirst()) {
3341a990a715012379451344246c5156d29938f12886Alice Yang                    mRefMessage = new Message(data);
3342a990a715012379451344246c5156d29938f12886Alice Yang                }
33439f855d667e34fbf0d330845225c26956e540b819Andy Huang                finishSetup(mComposeMode, getIntent(), mInnerSavedState);
3344a990a715012379451344246c5156d29938f12886Alice Yang                break;
3345b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3346b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3347b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3348b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3349faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3350faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3351b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3352b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3353dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3354b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3355b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3356b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3357b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3358b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3359b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3360b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3361b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3362faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3363faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3364faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3365b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3366b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3367b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3368b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3369b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3370b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3371b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3372b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3373b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3374b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3375b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3376b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3377b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3378b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3379b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3380b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
338196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3382b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3383b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3384b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
338596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
338696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
338796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3388b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3389b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3390b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3391b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3392b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3393b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3394b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3395b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3396b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3397b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3398b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3399b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
340096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
340196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
340296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
340396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
340483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
340583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
340683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
340783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
340883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
34091f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3410