ComposeActivity.java revision 7dd05b1b54673fe526ea35aa44e37827e8d38aa5
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/**
28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc.
38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License.
68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at
78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software
118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and
148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License.
158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */
168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose;
188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener;
215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
25b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment;
26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction;
2796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager;
286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
2982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
3196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader;
3282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader;
3582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
388e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
3982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor;
421ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable;
4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
46ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString;
4782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
48c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
4982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
5046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
51c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity;
5362d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent;
54326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
55b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
56b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
61b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection;
6262d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo;
63326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
648e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
65433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
67013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
687b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
69c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
715680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService;
725c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
731ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView;
7440882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener;
759932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
765a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
7730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
7833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
815680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder;
8247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider;
833ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
8482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
8592551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
86181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
8730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
883ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
8912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
901ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
9183e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity;
92fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity;
93b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment;
9492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
95434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils;
96febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask;
97b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
9830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
9930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
10046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
10182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
1024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
1038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException;
1053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException;
1068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
1078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
10846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
109bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
11046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
11175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
1141c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
115bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
11682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
11746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
11846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1195a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
120a990a715012379451344246c5156d29938f12886Alice Yang        AttachmentAddedOrDeletedListener, OnAccountChangedListener,
121a990a715012379451344246c5156d29938f12886Alice Yang        LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener,
122a990a715012379451344246c5156d29938f12886Alice Yang        FeedbackEnabledActivity {
1236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
12415f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int COMPOSE = -1;
12515f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY = 0;
12615f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int REPLY_ALL = 1;
12715f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int FORWARD = 2;
12815f505ba369523b6a3b3141221db9719c5e6db80mindyp    protected static final int EDIT_DRAFT = 3;
1296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
13196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    protected static final String EXTRA_ACTION = "action";
1326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
133326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_CC = "showCc";
134326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    private static final String EXTRA_SHOW_BCC = "showBcc";
1351623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private static final String EXTRA_RESPONDED_INLINE = "respondedInline";
1361d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp    private static final String EXTRA_SAVE_ENABLED = "saveEnabled";
137a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
146d27b6ea7fcc68b2af200158fab341c6e98727144mindyp    protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1479a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
14862066e47fe69c33b60ed970e46809ba81d044064Mark Wei    private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews";
14962066e47fe69c33b60ed970e46809ba81d044064Mark Wei
1508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
15882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
16482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
16682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
16882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
16982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
1701f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    // FIXME: values in this map are never read.
17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
1726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1766349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
178daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    public static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
180e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String EXTRA_ATTACHMENTS = "attachments";
181f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1825680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    /** If set, we will clear notifications for this folder. */
1835680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy    public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder";
1845680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
1853ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
18636bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
187b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // If this is a reply/forward then this extra will hold a uri we must query
188b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    // to get the original message.
189b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri";
190434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    // If this is an action to edit an existing draft message, this extra will hold the
191bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
192bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
194b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
195013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
196013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
197013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
199e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
2008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
201e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
202e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
203e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
204e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_END = null;
205e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
20696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    private static final int REFERENCE_MESSAGE_LOADER = 0;
207b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final int LOADER_ACCOUNT_CURSOR = 1;
208a990a715012379451344246c5156d29938f12886Alice Yang    private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2;
20947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
210b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private static final String TAG_WAIT = "wait-fragment";
2112db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_PHOTO = "image/*";
2122db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private static final String MIME_TYPE_VIDEO = "video/*";
2138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
21482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
21582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
21682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
21782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
218c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
219c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
220c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
2218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
2228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
2237b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
22433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
22592551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
226181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
22782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
2286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
2296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
230326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
231326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
23246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
23346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
23446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
235433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2361a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2372eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
238eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2391883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    @VisibleForTesting
2401883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira    protected FromAddressSpinner mFromSpinner;
241013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
242eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
24382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
24482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
24582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
24782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
248eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
249b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
250b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected Message mRefMessage;
2517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
25344a6339dd80f4b5b9e5d54567021698d92467c5emindyp    private ReplyFromAccount mDraftAccount;
2547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
25593b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mPhotoAttachmentsButton;
25693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp    private View mVideoAttachmentsButton;
2573ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
258326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
259daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view.
260daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook     */
261daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private boolean mLaunchedFromEmail = false;
262cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mToListener;
263cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mCcListener;
264cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private RecipientTextWatcher mBccListener;
265b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira    private Uri mRefMessageUri;
266a990a715012379451344246c5156d29938f12886Alice Yang    private boolean mShowQuotedText = false;
267b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private Bundle mSavedInstanceState;
268daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
269daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
2701623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // Array of the outstanding send or save tasks.  Access is synchronized
2711623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // with the object itself
2721623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    /* package for testing */
2731623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    @VisibleForTesting
2741623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
2751623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    // FIXME: this variable is never read. related to sRequestMessageIdMap.
2761623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private int mRequestId;
2771623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private String mSignature;
2781623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private Account[] mAccounts;
2791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp    private boolean mRespondedInline;
2801623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
281daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    /**
282326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
283326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2843ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
2851ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, EDIT_DRAFT, null, null);
286326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
287326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
29133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2921ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, null, COMPOSE, null, null);
2936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2980aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createReplyIntent(final Context launcher, final Account account,
2990aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final boolean isReplyAll) {
3000aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY);
3010aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3020aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3030aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3040aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    public static Intent createForwardIntent(final Context launcher, final Account account,
3070aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri) {
3080aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return createActionIntent(launcher, account, messageUri, FORWARD);
3090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3110aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private static Intent createActionIntent(final Context launcher, final Account account,
3120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy            final Uri messageUri, final int action) {
3130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        final Intent intent = new Intent(launcher, ComposeActivity.class);
3140aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3150aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3160aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_ACTION, action);
3170aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
3180aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri);
3190aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3200aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        return intent;
3210aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    }
3220aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy
3230aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    /**
3240aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     * Can be called from a non-UI thread.
3250aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy     */
3263ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
3271ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, REPLY, null, null);
3286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3333ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
3341ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, REPLY_ALL, null, null);
3356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
3386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
3396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
3403ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
3411ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, FORWARD, null, null);
3426349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
3441ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    public static void reportRenderingFeedback(Context launcher, Account account, Message message,
3451ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String body) {
3461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        launch(launcher, account, message, FORWARD, "android-gmail-readability@google.com", body);
3471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    }
3481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
3491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    private static void launch(Context launcher, Account account, Message message, int action,
3501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            String toAddress, String body) {
3516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
3526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
3536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
3546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
355bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
356bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
357bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
358bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
359bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
3601ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (toAddress != null) {
3611ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_TO, toAddress);
3621ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3631ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (body != null) {
3641ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            intent.putExtra(EXTRA_BODY, body);
3651ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
3666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
3676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
3688e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
3698e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
3708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
3718e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
3728e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
373b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mSavedInstanceState = savedInstanceState;
374b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        checkValidAccounts();
375b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
376b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
377b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void finishCreate() {
378b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        Bundle savedInstanceState = mSavedInstanceState;
37946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
380818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
381e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
38262066e47fe69c33b60ed970e46809ba81d044064Mark Wei        ArrayList<AttachmentPreview> previews;
383a990a715012379451344246c5156d29938f12886Alice Yang        mShowQuotedText = false;
384e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
38547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        // Check for any of the possibly supplied accounts.;
38647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
387f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (hadSavedInstanceStateMessage(savedInstanceState)) {
388e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
389e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
390e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
39162066e47fe69c33b60ed970e46809ba81d044064Mark Wei
39262066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = savedInstanceState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS);
393e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
394e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
39547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            account = obtainAccount(intent);
396e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
397e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
398e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
39962066e47fe69c33b60ed970e46809ba81d044064Mark Wei            previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS);
400e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
401b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira            mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI);
402e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
40362066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentsView.setAttachmentPreviews(previews);
40492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
40592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
406818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
407818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
408818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
409bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
4105680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        // Clear the notification and mark the conversation as seen, if necessary
4115680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        final Folder notificationFolder =
4125680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER);
4135680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        if (notificationFolder != null) {
4145680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            final Intent clearNotifIntent =
4155680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy                    new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS);
416d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy            clearNotifIntent.setPackage(getPackageName());
41748cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account);
41848cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy            clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder);
4195680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
4205680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy            startService(clearNotifIntent);
4215680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy        }
4225680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy
423daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) {
424daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            mLaunchedFromEmail = true;
425daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        } else if (Intent.ACTION_SEND.equals(intent.getAction())) {
426daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            final Uri dataUri = intent.getData();
427daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            if (dataUri != null) {
428daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String dataScheme = intent.getData().getScheme();
429daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                final String accountScheme = mAccount.composeIntentUri.getScheme();
430daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme);
431daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            }
432daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
433daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
43496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessageUri != null) {
435a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = true;
436a990a715012379451344246c5156d29938f12886Alice Yang            mComposeMode = action;
437a990a715012379451344246c5156d29938f12886Alice Yang            getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this);
43896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            return;
43996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else if (message != null && action != EDIT_DRAFT) {
440e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
441e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
442a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira            showCcBcc(savedInstanceState);
443a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
444e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
445e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
4468960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showBcc = !TextUtils.isEmpty(message.getBcc());
4478960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy            boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc());
448ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
449bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
450bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
451bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
452bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
453bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
454bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
455bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
456bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
457bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
458bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
459bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
460bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
461bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
462bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
463bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
464bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
465a990a715012379451344246c5156d29938f12886Alice Yang            LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action);
466a990a715012379451344246c5156d29938f12886Alice Yang
467a990a715012379451344246c5156d29938f12886Alice Yang            mShowQuotedText = message.appendRefMessageContent;
468a990a715012379451344246c5156d29938f12886Alice Yang            if (message.refMessageUri != null) {
469a990a715012379451344246c5156d29938f12886Alice Yang                // If we're editing an existing draft that was in reference to an existing message,
470a990a715012379451344246c5156d29938f12886Alice Yang                // still need to load that original message since we might need to refer to the
471a990a715012379451344246c5156d29938f12886Alice Yang                // original sender and recipients if user switches "reply <-> reply-all".
472a990a715012379451344246c5156d29938f12886Alice Yang                mRefMessageUri = message.refMessageUri;
473a990a715012379451344246c5156d29938f12886Alice Yang                mComposeMode = action;
474a990a715012379451344246c5156d29938f12886Alice Yang                getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this);
475a990a715012379451344246c5156d29938f12886Alice Yang                return;
476a990a715012379451344246c5156d29938f12886Alice Yang            }
477e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
478e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
4790aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                initFromRefMessage(action);
480a990a715012379451344246c5156d29938f12886Alice Yang                mShowQuotedText = true;
481e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
4828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
4838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
484bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
485a990a715012379451344246c5156d29938f12886Alice Yang
486a990a715012379451344246c5156d29938f12886Alice Yang        mComposeMode = action;
487a990a715012379451344246c5156d29938f12886Alice Yang        finishSetup(action, intent, savedInstanceState);
48896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
489bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
490b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void checkValidAccounts() {
491faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        final Account[] allAccounts = AccountUtils.getAccounts(this);
492faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook        if (allAccounts == null || allAccounts.length == 0) {
493b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this);
494b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (noAccountIntent != null) {
495faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                mAccounts = null;
496b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT);
497b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
498b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
49926d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp            // If none of the accounts are syncing, setup a watcher.
500b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            boolean anySyncing = false;
501faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            for (Account a : allAccounts) {
502dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                if (a.isAccountReady()) {
503b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    anySyncing = true;
504b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    break;
505b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
506b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
507b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (!anySyncing) {
508b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // There are accounts, but none are sync'd, which is just like having no accounts.
509b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                mAccounts = null;
510b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
511b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return;
512b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
513faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook            mAccounts = AccountUtils.getSyncingAccounts(this);
514b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finishCreate();
515b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
516b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
517b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
51847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    private Account obtainAccount(Intent intent) {
51947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Account account = null;
52047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        Object accountExtra = null;
52147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (intent != null && intent.getExtras() != null) {
52247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT);
52347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof Account) {
52447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                return (Account) accountExtra;
5257ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp            } else if (accountExtra instanceof String) {
5267ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                // This is the Account attached to the widget compose intent.
5277ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                account = Account.newinstance((String)accountExtra);
5287ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                if (account != null) {
5297ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                    return account;
5307ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp                }
53147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
5325ee9dc48884714e9005a1409e7002a0e04bad313mindyp            accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ?
5335ee9dc48884714e9005a1409e7002a0e04bad313mindyp                    intent.getStringExtra(Utils.EXTRA_ACCOUNT) :
5345ee9dc48884714e9005a1409e7002a0e04bad313mindyp                        intent.getStringExtra(EXTRA_SELECTED_ACCOUNT);
53547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
53647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        if (account == null) {
5370617446db14891bffaa2748e1fc98526aac1e06dmindyp            MailAppProvider provider = MailAppProvider.getInstance();
5380617446db14891bffaa2748e1fc98526aac1e06dmindyp            String lastAccountUri = provider.getLastSentFromAccount();
5390617446db14891bffaa2748e1fc98526aac1e06dmindyp            if (TextUtils.isEmpty(lastAccountUri)) {
5400617446db14891bffaa2748e1fc98526aac1e06dmindyp                lastAccountUri = provider.getLastViewedAccount();
5410617446db14891bffaa2748e1fc98526aac1e06dmindyp            }
54247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (!TextUtils.isEmpty(lastAccountUri)) {
54347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                accountExtra = Uri.parse(lastAccountUri);
54447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
54547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
546b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts != null && mAccounts.length > 0) {
54747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) {
54847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // For backwards compatibility, we need to check account
54947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // names.
550b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
55147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.name.equals(accountExtra)) {
55247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
55347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
55447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
55547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            } else if (accountExtra instanceof Uri) {
55647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // The uri of the last viewed account is what is stored in
55747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // the current code base.
558b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                for (Account a : mAccounts) {
55947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    if (a.uri.equals(accountExtra)) {
56047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                        account = a;
56147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    }
56247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
563b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
564b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (account == null) {
565b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                account = mAccounts[0];
56647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira            }
56747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        }
56847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira        return account;
56947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira    }
57047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira
571a990a715012379451344246c5156d29938f12886Alice Yang    private void finishSetup(int action, Intent intent, Bundle savedInstanceState) {
57234a3c56570eac4760405b3d5bff5fdc706a22facmindyp        setFocus(action);
573bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
574eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
57546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
576818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
577f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // Don't bother with the intent if we have procured a message from the
578f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        // intent already.
579f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        if (!hadSavedInstanceStateMessage(savedInstanceState)) {
580f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira            initAttachmentsFromIntent(intent);
581f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        }
582a990a715012379451344246c5156d29938f12886Alice Yang        initActionBar();
583e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
584e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
585d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
586d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // If this is a draft message, the draft account is whatever account was
587d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        // used to open the draft message in Compose.
588d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        if (mDraft != null) {
589d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp            mDraftAccount = mReplyFromAccount;
590d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp        }
591d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp
59275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
593326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        updateHideOrShowCcBcc();
594a990a715012379451344246c5156d29938f12886Alice Yang        updateHideOrShowQuotedText(mShowQuotedText);
5951623f9bfde8ced840a52820da28a0939bcaa32f9mindyp
5961623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = mSavedInstanceState != null ?
5971623f9bfde8ced840a52820da28a0939bcaa32f9mindyp                mSavedInstanceState.getBoolean(EXTRA_RESPONDED_INLINE) : false;
5981623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        if (mRespondedInline) {
5991623f9bfde8ced840a52820da28a0939bcaa32f9mindyp            mQuotedTextView.setVisibility(View.GONE);
6001623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        }
60171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    }
60271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira
603ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) {
604f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira        return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE);
605f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira    }
606f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira
60771c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira    private void updateHideOrShowQuotedText(boolean showQuotedText) {
60871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira        mQuotedTextView.updateCheckedState(showQuotedText);
60940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
610433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
611433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
612433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
613433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
614433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
615433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
616433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
617433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
618433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
619433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
620433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
621433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
622433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
623433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
624433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
625433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
626433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
627433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
628433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
629433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
6302708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                if (TextUtils.isEmpty(mTo.getText())) {
6312708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    mTo.requestFocus();
6322708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                    break;
6332708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp                }
634ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                //$FALL-THROUGH$
635433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
636433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
637433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
638433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
639433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
640433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
641433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
642433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
643433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
644433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
645433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
646433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
647433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
648433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
649433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
650433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
651433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
652433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
653433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
654433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
6558743cfca851058d50385951b111dd903b1fa6c5amindyp        } else if (length >= 0) {
656433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
657433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
658433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
6591a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6601a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
6611a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
6621a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
6631a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
6641a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
6651a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
666818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
667b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount, mAccounts);
668818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
6691a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
6701a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
671eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
672eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
673eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
674eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
675eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
676eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
677eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
678eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
679eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
680eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
681a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        // When the user exits the compose view, see if this draft needs saving.
6823d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        // Don't save unnecessary drafts if we are only changing the orientation.
6833d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee        if (!isChangingConfigurations()) {
684a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            saveIfNeeded();
685a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira        }
686eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
687eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
688eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
689eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
690b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) {
691eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
692b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            mAddingAttachment = false;
693b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else if (request == RESULT_CREATE_ACCOUNT) {
694a990a715012379451344246c5156d29938f12886Alice Yang            // We were waiting for the user to create an account
695b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            if (result != RESULT_OK) {
696b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                finish();
697b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            } else {
698b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // Watch for accounts to show up!
699b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                // restart the loader to get the updated list of accounts
700b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this);
701b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                showWaitFragment(null);
702b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            }
703eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
704eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
705eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
706eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
707e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
70847db6d764dd4b74ddfd7fda6412e32d84d86fc9amindyp        clearChangeListeners();
709e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
710e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (savedInstanceState != null) {
711e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
712e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
713e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
714e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
715e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
716e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
717e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
718e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
719e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
720e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
721e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
722e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7231d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        initChangeListeners();
724e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
725e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
726e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
727eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
728eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
729b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // We have no accounts so there is nothing to compose, and therefore, nothing to save.
730b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
731b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return;
732b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
733e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
734e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
735e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
736e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
737e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
738e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
739e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
740e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
741e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
7426273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
7436273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
744151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
745d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira        final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null
746d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
747d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira                        replyFromAccounts.get(selectedPos) : null;
748e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
749e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
750e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
751e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
752e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
753e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
754e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
755eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
756e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
757e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
758e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
760e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
761e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
762e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
763e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
764e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
765e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
766e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
767e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        final Message message = createMessage(selectedReplyFromAccount, mode);
7681f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        if (mDraft != null) {
769e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.id = mDraft.id;
770e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.serverId = mDraft.serverId;
771e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp            message.uri = mDraft.uri;
7721f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        }
773e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
774e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
776e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
777e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
778326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible());
779326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible());
7801623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline);
781816b3f0adc04db073820f04ce379e5126e1cbef1mindyp        state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled());
78262066e47fe69c33b60ed970e46809ba81d044064Mark Wei        state.putParcelableArrayList(
78362066e47fe69c33b60ed970e46809ba81d044064Mark Wei                EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews());
784e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
785e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
786e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
787e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
789e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar != null
790e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
791e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
792e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
793e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
794e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
795e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
799d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang        message.serverId = null;
800e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
801e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
802e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
803e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
8048960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8058960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8068960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
8078960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setReplyTo(null);
808e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
809b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText()));
810b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final StringBuilder fullBody = new StringBuilder(htmlBody);
811e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
812e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
813e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
814a990a715012379451344246c5156d29938f12886Alice Yang        message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null;
815e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
816e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
820e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
821e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
824e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
825e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
8268960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address
8278960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                : mAccount != null ? mAccount.name : null);
8281f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        message.draftType = getDraftType(mode);
8298960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setTo(formatSenders(mTo.getText().toString()));
8308960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setCc(formatSenders(mCc.getText().toString()));
8318960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        message.setBcc(formatSenders(mBcc.getText().toString()));
832e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp        return message;
8331f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang    }
8341f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang
835ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static String formatSenders(final String string) {
8363c9115813343861a44133b805fb9f55512d20948Mindy Pereira        if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') {
8373c9115813343861a44133b805fb9f55512d20948Mindy Pereira            return string.substring(0, string.length() - 1);
8383c9115813343861a44133b805fb9f55512d20948Mindy Pereira        }
8393c9115813343861a44133b805fb9f55512d20948Mindy Pereira        return string;
8403c9115813343861a44133b805fb9f55512d20948Mindy Pereira    }
8413c9115813343861a44133b805fb9f55512d20948Mindy Pereira
842818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
843818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
844bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
845bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
846bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
84723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
84823e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
849b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
850b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
85123e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
852fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        if (mAccount != null) {
853f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal            MailActivity.setNfcMessage(mAccount.name);
854fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira        }
855818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
856818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
857e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
8589a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        String accountString = null;
859e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
86062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
86162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
862b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount, mAccounts);
8639a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
8649a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
8659a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
8669a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
8679a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
8689a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
8699a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
8709a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
871e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
872e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
873e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
874e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
875e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
876e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
877e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
87862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
87962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
880238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang            mReplyFromAccount = getDefaultReplyFromAccount(mAccount);
88162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
8829a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
88362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
8849a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
88562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
886a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
887a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
88862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
88962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
890a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
89162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
892a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
893a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
894a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
895a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
896a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
89746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
89846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
89962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
90062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
90162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
90262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
90362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
90462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
90562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
90662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
90762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
90862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
90962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
91062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
91162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
91262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
91362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
91462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
91562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
91662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
91762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
91862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
91962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
92062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
92162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
92262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
92362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
924326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (mCachedSettings.forceReplyFromDefault) {
92562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
92662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
92789bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira            // If we aren't explicitly told which account to look for, look at
92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
92962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
93062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
9315ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getToAddresses()));
9325ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp            allRecipients.addAll(Arrays.asList(refMessage.getCcAddresses()));
93362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
93462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
93562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
93662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
93762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
93862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
93962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
94062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
94162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
94262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
94362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
94562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
94662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
94762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
94962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
95062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
95162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
95262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
95362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
95462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
95562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
9561617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        customFroms = account.getReplyFroms();
9571617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang        if (customFroms != null) {
9581617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang            for (ReplyFromAccount entry : customFroms) {
9591617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                if (recipientsMap.contains(entry.address)) {
9601617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingReplyFrom = entry;
9611617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang                    matchingAddressCount++;
96262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
96462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
96562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
96762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
96962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
97062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
971ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) {
972ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final ReplyFromAccount from : account.getReplyFroms()) {
97362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
97462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
97562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
97662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
977cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name,
978cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                true, false);
97962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
98062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
981e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
9828960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String sender = msg.getFrom();
98362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
98462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
98562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
98662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
987cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira                    mAccount.name, mAccount.name, true, false);
98862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
98962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
99062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
99162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
99262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
99362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
99662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
99862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
99946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
1000b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        findViewById(R.id.compose).setVisibility(View.VISIBLE);
1001a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
10028e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
10038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
10048e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
10058e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
10067b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
100793b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment);
1008cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mPhotoAttachmentsButton != null) {
1009cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mPhotoAttachmentsButton.setOnClickListener(this);
1010cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
101193b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp        mVideoAttachmentsButton = findViewById(R.id.add_video_attachment);
1012cd0b0b950efebfc3964334067747b97e61c4f027mindyp        if (mVideoAttachmentsButton != null) {
1013cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mVideoAttachmentsButton.setOnClickListener(this);
1014cd0b0b950efebfc3964334067747b97e61c4f027mindyp        }
1015818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
1016818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
1017818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
101882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
101982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
10206349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
102162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        mSubject.setOnEditorActionListener(this);
102246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
102346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
1024433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
10251a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
10262eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
1027eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
10285a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
1029326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1030326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
103162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    @Override
103262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) {
103362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        if (action == EditorInfo.IME_ACTION_DONE) {
103462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            focusBody();
103562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp            return true;
103662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        }
103762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp        return false;
103862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp    }
103962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp
1040e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    protected TextView getBody() {
1041e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mBodyView;
1042e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1043e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1044e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1045e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public Account getFromAccount() {
1046e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        return mReplyFromAccount != null && mReplyFromAccount.account != null ?
1047e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira                mReplyFromAccount.account : mAccount;
1048e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
1049e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
1050cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    private void clearChangeListeners() {
1051cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mSubject.removeTextChangedListener(this);
1052cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBodyView.removeTextChangedListener(this);
1053cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.removeTextChangedListener(mToListener);
1054cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.removeTextChangedListener(mCcListener);
1055cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.removeTextChangedListener(mBccListener);
1056cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mFromSpinner.setOnAccountChangedListener(null);
1057cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mAttachmentsView.setAttachmentChangesListener(null);
1058cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira    }
1059cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira
106075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
106175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
106275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
106375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
10641d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        // Make sure we only add text changed listeners once!
10651d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        clearChangeListeners();
106675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
106775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
1068cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mToListener == null) {
1069cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mToListener = new RecipientTextWatcher(mTo, this);
1070cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1071cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mTo.addTextChangedListener(mToListener);
1072cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mCcListener == null) {
1073cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mCcListener = new RecipientTextWatcher(mCc, this);
1074cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1075cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mCc.addTextChangedListener(mCcListener);
1076cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        if (mBccListener == null) {
1077cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira            mBccListener = new RecipientTextWatcher(mBcc, this);
1078cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        }
1079cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        mBcc.addTextChangedListener(mBccListener);
108075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
1081818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
108275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
108375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
1084a990a715012379451344246c5156d29938f12886Alice Yang    private void initActionBar() {
1085a990a715012379451344246c5156d29938f12886Alice Yang        LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity");
1086eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
1087e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (actionBar == null) {
1088e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            return;
1089e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
1090a990a715012379451344246c5156d29938f12886Alice Yang        if (mComposeMode == ComposeActivity.COMPOSE) {
1091eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
1092eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
1093326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1094eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
1095326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
1096326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
1097326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1098eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
1099eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
1100a990a715012379451344246c5156d29938f12886Alice Yang            switch (mComposeMode) {
1101326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
1102eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
1103326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1104326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
1105eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
1106326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1107326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
1108eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
1109326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
1110326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
11116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1112fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
1113fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
1114fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
11156349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
11166349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
11170aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void initFromRefMessage(int action) {
11180aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        setFieldsFromRefMessage(action);
11191ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
11201ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // Check if To: address and email body needs to be prefilled based on extras.
11211ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        // This is used for reporting rendering feedback.
11221ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) {
11231ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            Intent intent = getIntent();
11241ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            if (intent.getExtras() != null) {
11251ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String toAddresses = intent.getStringExtra(EXTRA_TO);
11261ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (toAddresses != null) {
11271ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ",")));
11281ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11291ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                String body = intent.getStringExtra(EXTRA_BODY);
11301ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                if (body != null) {
11311ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                    setBody(body, false /* withSignature */);
11321ebc2db723ed29093d724eb5da906a496ee57224Alice Yang                }
11331ebc2db723ed29093d724eb5da906a496ee57224Alice Yang            }
11341ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        }
11351ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
113696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        if (mRefMessage != null) {
113796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // CC field only gets populated when doing REPLY_ALL.
113896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // BCC never gets auto-populated, unless the user is editing
113996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            // a draft with one.
114029a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira            if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) {
114196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                mCcBccView.show(false, true, false);
114296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            }
114396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
114496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        updateHideOrShowCcBcc();
114596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
114696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
11470aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    private void setFieldsFromRefMessage(int action) {
11488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
11498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
11508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
11518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
11528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
11530aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy        initRecipientsFromRefMessage(mRefMessage, action);
1154e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
11558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
11568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
11576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
1158c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
1159c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
1160e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
11611f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message);
1162bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
1163bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
1164bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
1165bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
1166bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
1167bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
1168bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
1169bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
1170bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
11712421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
11722421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
11732421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
11745c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
11752421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
11762421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1177cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira        int quotedTextIndex = message.appendRefMessageContent ?
1178002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                message.quotedTextOffset : -1;
1179bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
1180002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        CharSequence quotedText = null;
1181bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
1182752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            CharSequence htmlText = "";
1183002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1184752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                // Find the offset in the htmltext of the actual quoted text and strip it out.
1185752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml);
1186752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                if (quotedTextIndex > -1) {
1187c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0,
1188c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                            quotedTextIndex));
1189752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    quotedText = message.bodyHtml.subSequence(quotedTextIndex,
1190752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyHtml.length());
1191752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                }
11921a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira            } else {
1193c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                htmlText = Utils.convertHtmlToPlainText(message.bodyHtml);
1194002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1195002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(htmlText);
1196bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
1197752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final String body = message.bodyText;
1198752222d839d9afeb5c4665669eab81645e413495Mindy Pereira            final CharSequence bodyText = !TextUtils.isEmpty(body) ?
1199752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                    (quotedTextIndex > -1 ?
1200752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            message.bodyText.substring(0, quotedTextIndex) : message.bodyText)
1201752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                            : "";
1202002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            if (quotedTextIndex > -1) {
1203752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex)
1204752222d839d9afeb5c4665669eab81645e413495Mindy Pereira                        : null;
1205002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            }
1206002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            mBodyView.setText(bodyText);
1207002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
1208002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        if (quotedTextIndex > -1 && quotedText != null) {
12093971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira            mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward);
1210bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
1211bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1212bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
12138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
12148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
12158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
12168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
12178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
12188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
12198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
12208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
12218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
12228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
12238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
12248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
12258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
12268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
12278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
12288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
12298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
12308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
12310b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
12328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
12338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
12348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
1235dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
12368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
12378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
12428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
12448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
12468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
12488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
12508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
12518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
12528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
12558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
12568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
12578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
12608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
12618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
12628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
1263dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
1265dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
1267dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
12808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
12828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
1283e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
1284e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
12858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
1287a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // TODO: handle the case where there are spaces in the display name as
1288a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>"
1289a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        // as they could be encoded ambiguously.
12908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
12928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
1293a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        try {
12947dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee            return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME);
1295a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        } catch (IllegalArgumentException e) {
1296a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
1297a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s);
1298a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            } else {
1299a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
1300a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
1301a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            return null;
1302a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira        }
13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
13067dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from
13077dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * changing '+' into ' '
13087dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     *
13097dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @param toReplace Input string
13107dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     * @return The string with all "+" characters replaced with "%2B"
13117dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee     */
13127dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    private String replacePlus(String toReplace) {
13137dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee        return toReplace.replace("+", "%2B");
13147dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    }
13157dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee
13167dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee    /**
13178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
13188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
13198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
13208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
13218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
13228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
13238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
13248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
13258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
13268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
13278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
13288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
13298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
13308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
13318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
13338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1334a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            if (!TextUtils.isEmpty(to)) {
1335a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira                addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
1336a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira            }
13378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
13388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
13398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
13408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
13418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
13468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
13508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
13528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
13538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
13568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13577dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)),
13587dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                        UTF8_ENCODING_NAME));
13598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
13687dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee                setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME),
13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1376bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
1377bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected void initAttachments(Message refMessage) {
1378434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        addAttachments(refMessage.getAttachments());
1379434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    }
1380434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei
1381434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    public long addAttachments(List<Attachment> attachments) {
1382434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        long size = 0;
1383434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        AttachmentFailureException error = null;
1384434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        for (Attachment a : attachments) {
1385434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            try {
1386434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                size += mAttachmentsView.addAttachment(mAccount, a);
1387434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } catch (AttachmentFailureException e) {
1388434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                error = e;
1389434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
1390434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        }
1391434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        if (error != null) {
1392434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            LogUtils.e(LOG_TAG, error, "Error adding attachment");
1393434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            if (attachments.size() > 1) {
1394434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(R.string.too_large_to_attach_multiple);
1395434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            } else {
1396434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                showAttachmentTooBigToast(error.getErrorRes());
1397434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            }
13983cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        }
1399434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        return size;
14003cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14013cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
14023cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    /**
14033cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * When an attachment is too large to be added to a message, show a toast.
14043cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * This method also updates the position of the toast so that it is shown
14053cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     * clearly above they keyboard if it happens to be open.
14063cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira     */
1407434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showAttachmentTooBigToast(int errorRes) {
1408434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        String maxSize = AttachmentUtils.convertToHumanReadableSize(
1409434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                getApplicationContext(), mAccount.settings.getMaxAttachmentSize());
1410434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        showErrorToast(getString(errorRes, maxSize));
14113cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira    }
14123cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira
1413434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei    private void showErrorToast(String message) {
1414434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG);
1415434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei        t.setText(message);
14163cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.setGravity(Gravity.CENTER_HORIZONTAL, 0,
14173cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira                getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset));
14183cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira        t.show();
1419eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1420eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1421f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
142203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
142303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
142403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
142503ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
1426f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
1427f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
1428f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
1429f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
1430f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
1431f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
1432f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
1433f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1434f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14355c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
1436f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1437f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1438434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                        showAttachmentTooBigToast(e.getErrorRes());
1439f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1440f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1441f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1442f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
14439a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp            if (extras.containsKey(Intent.EXTRA_STREAM)) {
14449a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
14459a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Parcelable> uris = extras
14469a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            .getParcelableArrayList(Intent.EXTRA_STREAM);
14479a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    ArrayList<Attachment> attachments = new ArrayList<Attachment>();
14489a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    for (Parcelable uri : uris) {
14499a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        try {
14509a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri));
14519a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        } catch (AttachmentFailureException e) {
14529a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
14539a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            String maxSize = AttachmentUtils.convertToHumanReadableSize(
14549a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    getApplicationContext(),
14559a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    mAccount.settings.getMaxAttachmentSize());
14569a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                            showErrorToast(getString
14579a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                                    (R.string.generic_attachment_problem, maxSize));
14589a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        }
14599a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    }
14609a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += addAttachments(attachments);
14619a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                } else {
14629a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
14639a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    long size = 0;
1464f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
14659a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        size = mAttachmentsView.addAttachment(mAccount, uri);
1466f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1467f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
14689a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                        showAttachmentTooBigToast(e.getErrorRes());
1469f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
14709a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp                    totalSize += size;
1471f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1472f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1473f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1474f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1475f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1476f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1477f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1478f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1479f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1480f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1481f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1482e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1483e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
14849932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
14859932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
148646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
148746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
148846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1489ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1490326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean ccVisible = mCcBccView.isCcVisible();
1491326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        boolean bccVisible = mCcBccView.isBccVisible();
1492ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1493326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (!ccVisible || !bccVisible) {
1494ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1495326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label
1496ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1497ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1498cd0b0b950efebfc3964334067747b97e61c4f027mindyp                mCcBccButton.setVisibility(View.INVISIBLE);
1499ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1500ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
150146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
150246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1503a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1504326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC)) {
1505326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showCc = state.getBoolean(EXTRA_SHOW_CC);
1506326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC);
1507326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            if (showCc || showBcc) {
1508326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira                mCcBccView.show(false, showCc, showBcc);
1509326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira            }
1510326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira        }
1511326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira    }
1512326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira
1513013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1514013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1515013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1516013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1517013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
15182421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
15192421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
15202421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
15215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
15225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
15232421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
15242421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1525013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
15265c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
15275c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
15285c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1529434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showErrorToast(getResources().getString(
1530434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    e.getErrorRes(),
1531434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                    AttachmentUtils.convertToHumanReadableSize(
1532434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei                            getApplicationContext(), mAccount.settings.getMaxAttachmentSize())));
15335c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
15345c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
15355c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
15365c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
15375c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
1538434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            long size = mAttachmentsView.addAttachment(mAccount, attachment);
15399932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
15409932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
15419932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1542013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
15439932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
15449932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1545434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei            showAttachmentTooBigToast(e.getErrorRes());
1546013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1547013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1548013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
15490aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy    void initRecipientsFromRefMessage(Message refMessage, int action) {
15504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
15514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
15524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
15534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
1554ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        initReplyRecipients(refMessage, action);
15554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1557818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
1558ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    void initReplyRecipients(final Message refMessage, final int action) {
15595ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp        String[] sentToAddresses = refMessage.getToAddresses();
1560a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
156165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        String replytoAddress = refMessage.getReplyTo();
156265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        // If there is no reply to address, the reply to address is the sender.
156365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (TextUtils.isEmpty(replytoAddress)) {
156465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            replytoAddress = refMessage.getFrom();
156565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        }
15664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
15684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
15694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1570a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1571a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
1572ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            toAddresses = initToRecipients(refMessage.getFrom(), replytoAddress, sentToAddresses);
1573a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1574a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
15754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
1576ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            toAddresses = initToRecipients(refMessage.getFrom(), replytoAddress, sentToAddresses);
1577154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
1578ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, sentToAddresses);
1579ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            addRecipients(ccAddresses, refMessage.getCcAddresses());
15804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
15814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
15824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
15854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
15864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
15884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
15898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
15908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
15914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
15924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1593bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1594bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1595bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1596bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
15974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
15984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
15994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
16004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
16014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
16038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
16074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
16084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
16108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
16118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
16128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
16138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
16148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
16158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
16168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
16178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
16188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
16198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
16208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
16214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1624ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) {
1625ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final HashSet<String> hash = new HashSet<String>();
1626ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final Rfc822Token[] tokens : list) {
16274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
16284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
16294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
16304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
16324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
16354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
16364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
16374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
16394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
16404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
16424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
16454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
16464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
16474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
16484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1651ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private static void addAddressToList(final String address, final RecipientEditTextView list) {
16524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
16534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
16544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1655ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
16564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
16584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
16594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
16624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
1663ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    protected Collection<String> initToRecipients(final String fullSenderAddress,
1664ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            final String replyToAddress, final String[] inToAddresses) {
16654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
16664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
16674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
16684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
16694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
16704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
167165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp        if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) {
16723ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
16734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
167465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // In this case, the user is replying to a message in which their
167565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // current account or one of their custom from addresses is the only
167665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // recipient and they sent the original message.
167765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress)
167865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    && recipientMatchesThisAccount(inToAddresses[0])) {
167965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                toAddresses.add(inToAddresses[0]);
168065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                return toAddresses;
168165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            }
168265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // This happens if the user replies to a message they originally
168365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // wrote. In this case, "reply" really means "re-send," so we
168465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // target the original recipients. This works as expected even
168565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            // if the user sent the original message to themselves.
168665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp            for (String address : inToAddresses) {
168765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                if (!recipientMatchesThisAccount(address)) {
168865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp                    toAddresses.add(address);
1689fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                }
16901469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira            }
16914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
16924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
16934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
16944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1695ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void addRecipients(final Set<String> recipients, final String[] addresses) {
1696ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : addresses) {
1697cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // Do not add this account, or any of its custom from addresses, to
1698cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira            // the list of recipients.
16994a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
17005ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp            if (!recipientMatchesThisAccount(recipientAddress)) {
17014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
17024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
17034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
170446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
170546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1706cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    /**
1707cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * A recipient matches this account if it has the same address as the
1708cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * currently selected account OR one of the custom from addresses associated
1709cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * with the currently selected account.
1710cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param accountAddress currently selected account
1711cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @param recipientAddress address we are comparing with the currently selected account
1712cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     * @return
1713cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira     */
17145ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp    protected boolean recipientMatchesThisAccount(String recipientAddress) {
17155ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp        return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress,
1716fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp                        mAccount.getReplyFroms());
1717cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira    }
1718cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira
17193ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
17203ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
172146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
172246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
172346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
172446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
172546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
172646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
172746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
172846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
172946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
173046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
173146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
1732c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira        if (!TextUtils.isEmpty(subject)
1733c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira                && subject.toLowerCase().startsWith(prefix.toLowerCase())) {
173446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
173546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
173646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
173746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
173846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
173946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
174046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
174146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1742818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1743818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1744818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1745818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1746eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1747eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1748818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1749679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
1750c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
175182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1752679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
175333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
175433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1755c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
175633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1757c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
175882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1759c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
176082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
17618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
17628e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17638e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
17648e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
17658e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
17668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1767a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
17688e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
17698e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1770a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
17718e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
1772cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_photo_attachment:
1773cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_PHOTO);
1774cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
1775cd0b0b950efebfc3964334067747b97e61c4f027mindyp            case R.id.add_video_attachment:
1776cd0b0b950efebfc3964334067747b97e61c4f027mindyp                doAttach(MIME_TYPE_VIDEO);
1777cd0b0b950efebfc3964334067747b97e61c4f027mindyp                break;
17788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
17798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1780b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1781b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1782b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1783b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1784b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // Don't render any menu items when there are no accounts.
1785b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (mAccounts == null || mAccounts.length == 0) {
1786b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            return true;
1787b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1788b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1789b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
17901d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
17911d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        /*
17921d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * Start save in the correct enabled state.
17931d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 1) If a user launches compose from within gmail, save is disabled
17941d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * until they add something, at which point, save is enabled, auto save
17951d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * on exit; if the user empties everything, save is disabled, exiting does not
17961d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * auto-save
17971d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 2) if a user replies/ reply all/ forwards from within gmail, save is
17981d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled until they change something, at which point, save is
17991d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18001d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save.
18011d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * 3) If a user launches compose from another application and something
18021d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * gets populated (attachments, recipients, body, subject, etc), save is
18031d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * enabled, auto save on exit; if the user empties everything, save is
18041d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         * disabled, exiting does not auto-save
18051d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp         */
180682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
18071d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        String action = getIntent() != null ? getIntent().getAction() : null;
18081d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp        enableSave(mSavedInstanceState != null ?
18091d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                mSavedInstanceState.getBoolean(EXTRA_SAVE_ENABLED)
18101d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                    : (Intent.ACTION_SEND.equals(action)
18111d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SEND_MULTIPLE.equals(action)
18121d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || Intent.ACTION_SENDTO.equals(action)
18131d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp                            || shouldSave()));
18141d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp
181582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
18163ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
18173ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
18183ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
18193ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
18203ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
18213ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
18223ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
18233ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
18243ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
18253ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1826b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1827b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1828b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1829b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1830ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1831ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1832818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1833ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1834ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1835ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1836ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1837ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1838ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1839ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1840ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1841ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1842ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1843ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1844ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1845ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1846ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1847ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1848b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1849b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
185075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1851b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
18522db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_photo_attachment:
18532db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_PHOTO);
18542db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                break;
18552db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira            case R.id.add_video_attachment:
18562db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira                doAttach(MIME_TYPE_VIDEO);
18577b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1858ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1859ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1860b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
186133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
186248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira                doSave(true);
186333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
186433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
186533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
186675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1867efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1868efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1869efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
18701f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
18711f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
18721f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1873fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1874daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                onAppUpPressed();
1875fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1876fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
187730745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook                Utils.showHelp(this, mAccount, getString(R.string.compose_help_context));
1878fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1879fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
188017beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook                Utils.sendFeedback(this, mAccount, false);
1881fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
188275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
188375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
188433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1885b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1886b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1887b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1888326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1889b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    @Override
1890b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    public void onBackPressed() {
1891b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        // If we are showing the wait fragment, just exit.
1892b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (getWaitFragment() != null) {
1893b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            finish();
1894b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        } else {
1895b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            super.onBackPressed();
1896b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
1897b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
1898b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
18991672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal    /**
19001672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     * Carries out the "up" action in the action bar.
19011672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal     */
1902daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    private void onAppUpPressed() {
1903daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        if (mLaunchedFromEmail) {
1904daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // If this was started from Gmail, simply treat app up as the system back button, so
1905daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            // that the last view is restored.
1906daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            onBackPressed();
1907daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook            return;
1908daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        }
1909daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
1910daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Fire the main activity to ensure it launches the "top" screen of mail.
1911daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // Since the main Activity is singleTask, it should revive that task if it was already
1912daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        // started.
19130c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal        final Intent mailIntent = Utils.createViewInboxIntent(mAccount);
1914daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
1915daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
1916daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        startActivity(mailIntent);
1917daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook        finish();
1918daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook    }
1919daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook
192033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
1921dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(false, true, false, false);
192233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
192333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
192448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    private void doSave(boolean showToast) {
1925dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei        sendOrSaveWithSanityChecks(true, showToast, false, false);
192648e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira    }
192748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira
1928e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1929e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public interface SendOrSaveCallback {
193082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
19317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
19327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
193382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
193482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
193582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1936e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
1937e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveTask implements Runnable {
193882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
193982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
1940e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveCallback mSendOrSaveCallback;
1941e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
1942e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final SendOrSaveMessage mSendOrSaveMessage;
194344a6339dd80f4b5b9e5d54567021698d92467c5emindyp        private ReplyFromAccount mExistingDraftAccount;
194482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
194582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
194644a6339dd80f4b5b9e5d54567021698d92467c5emindyp                SendOrSaveCallback callback, ReplyFromAccount draftAccount) {
194782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
194882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
194982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
195044a6339dd80f4b5b9e5d54567021698d92467c5emindyp            mExistingDraftAccount = draftAccount;
195182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
195282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
195382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
195482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
19557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
195682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
195792551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
19587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
19597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
196082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
196182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
196282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
196344a6339dd80f4b5b9e5d54567021698d92467c5emindyp            if (mExistingDraftAccount != null
196444a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) {
196582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
196682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
196782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
196882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
1969febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                    if (mExistingDraftAccount.account.expungeMessageUri != null) {
1970febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                        new ContentProviderTask.UpdateTask()
1971febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                .run(resolver, mExistingDraftAccount.account.expungeMessageUri,
1972febd226e871263aeb21d436bee81eb2f7dec3d03mindyp                                        values, null, null);
1973cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1974cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1975eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
197682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
197782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
197882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
197982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
198082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
198182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
1982ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy            sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount);
198372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
198472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            if (!sendOrSaveMessage.mSave) {
198572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
198672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
198772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
198872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
198972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                UIProvider.incrementRecipientsTimesContacted(mContext,
199072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
199172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            }
199272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
199372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
199472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
199572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
199672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Send or Save a message.
199772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
1998ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private void sendOrSaveMessage(final long messageIdToSave,
1999ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) {
200072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final ContentResolver resolver = mContext.getContentResolver();
200172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID;
200272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
200372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final String accountMethod = sendOrSaveMessage.mSave ?
200472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SAVE_MESSAGE :
200572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    UIProvider.AccountCallMethods.SEND_MESSAGE;
200672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            try {
20083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (updateExistingMessage) {
20093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
20103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2011013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    callAccountSendSaveMethod(resolver,
20123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
201372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
2014013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook                    Uri messageUri = null;
20153c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final Bundle result = callAccountSendSaveMethod(resolver,
20163c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            selectedAccount.account, accountMethod, sendOrSaveMessage);
20173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (result != null) {
20183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // If a non-null value was returned, then the provider handled the call
20193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        // method
20203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        messageUri = result.getParcelable(UIProvider.MessageColumns.URI);
20213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
20223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (sendOrSaveMessage.mSave && messageUri != null) {
20233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        final Cursor messageCursor = resolver.query(messageUri,
20243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                UIProvider.MESSAGE_PROJECTION, null, null, null);
20253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        if (messageCursor != null) {
20263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            try {
20273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                if (messageCursor.moveToFirst()) {
20283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // Broadcast notification that a new message has
20293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    // been allocated
20303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                    mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
20313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                            new Message(messageCursor));
20323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                }
20333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            } finally {
20343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                                messageCursor.close();
20353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            }
20363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        }
20373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    }
203872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
20393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            } finally {
20403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                // Close any opened file descriptors
20413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                closeOpenedAttachmentFds(sendOrSaveMessage);
20423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
20443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
2045ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) {
20463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle openedFds = sendOrSaveMessage.attachmentFds();
20473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (openedFds != null) {
20483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                final Set<String> keys = openedFds.keySet();
2049ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                for (final String key : keys) {
20503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    final ParcelFileDescriptor fd = openedFds.getParcelable(key);
20513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    if (fd != null) {
2052ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
20533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            fd.close();
20543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        } catch (IOException e) {
20553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                            // Do nothing
2056ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
20577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
20587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
205982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
206072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        }
206182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
206272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook        /**
206372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * Use the {@link ContentResolver#call()} method to send or save the message.
206472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         *
206572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         * If this was successful, this method will return an non-null Bundle instance
206672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook         */
2067ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle callAccountSendSaveMethod(final ContentResolver resolver,
2068ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final Account account, final String method,
2069ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final SendOrSaveMessage sendOrSaveMessage) {
207072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            // Copy all of the values from the content values to the bundle
207172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size());
207272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet();
207372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
207472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            for (Entry<String, Object> entry : valueSet) {
207572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final Object entryValue = entry.getValue();
207672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                final String key = entry.getKey();
207772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                if (entryValue instanceof String) {
207872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putString(key, (String)entryValue);
207972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Boolean) {
208072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putBoolean(key, (Boolean)entryValue);
208172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Integer) {
208272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putInt(key, (Integer)entryValue);
208372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else if (entryValue instanceof Long) {
208472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    methodExtras.putLong(key, (Long)entryValue);
208572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                } else {
208672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                    LogUtils.wtf(LOG_TAG, "Unexpected object type: %s",
208772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                            entryValue.getClass().getName());
208872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook                }
208982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
209072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook
20913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            // If the SendOrSaveMessage has some opened fds, add them to the bundle
20923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle fdMap = sendOrSaveMessage.attachmentFds();
20933c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (fdMap != null) {
20943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                methodExtras.putParcelable(
20953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                        UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap);
20963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
20973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
209872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook            return resolver.call(account.uri, method, account.uri.toString(), methodExtras);
209982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
210082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
210182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2102e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    @VisibleForTesting
2103e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static class SendOrSaveMessage {
210492551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
210582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
21063ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
2107e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        @VisibleForTesting
2108e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        public final boolean mSave;
210982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
21103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        private final Bundle mAttachmentFds;
211182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
21123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values,
21133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                String refMessageId, List<Attachment> attachments, boolean save) {
211482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
211582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
211682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
211782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
211882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
21193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            mAttachmentFds = initializeAttachmentFds(context, attachments);
212182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
212282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
212382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
212482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
21263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        Bundle attachmentFds() {
21283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return mAttachmentFds;
21293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
21303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        /**
21323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Opens {@link ParcelFileDescriptor} for each of the attachments.  This method must be
21333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * called before the ComposeActivity finishes.
21343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         * Note: The caller is responsible for closing these file descriptors.
21353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook         */
2136ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        private static Bundle initializeAttachmentFds(final Context context,
2137ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                final List<Attachment> attachments) {
21383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            if (attachments == null || attachments.size() == 0) {
21393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                return null;
21403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final Bundle result = new Bundle(attachments.size());
21433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            final ContentResolver resolver = context.getContentResolver();
21443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            for (Attachment attachment : attachments) {
21463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (attachment == null || Utils.isEmpty(attachment.contentUri)) {
21473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    continue;
21483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                ParcelFileDescriptor fileDescriptor;
21513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                try {
21523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r");
21533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                } catch (FileNotFoundException e) {
21543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment");
21553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    fileDescriptor = null;
2156c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                } catch (SecurityException e) {
2157c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // We have encountered a security exception when attempting to open the file
2158c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // specified by the content uri.  If the attachment has been cached, this
2159c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // isn't a problem, as even through the original permission may have been
2160c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // revoked, we have cached the file.  This will happen when saving/sending
2161c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // a previously saved draft.
2162c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // TODO(markwei): Expose whether the attachment has been cached through the
2163c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // attachment object.  This would allow us to limit when the log is made, as
2164c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // if the attachment has been cached, this really isn't an error
2165c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment");
2166c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // Just set the file descriptor to null, as the underlying provider needs
2167c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    // to handle the file descriptor not being set.
2168c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook                    fileDescriptor = null;
21693c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                if (fileDescriptor != null) {
21723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                    result.putParcelable(attachment.contentUri.toString(), fileDescriptor);
21733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                }
21743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            }
21753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook
21763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook            return result;
21773c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        }
217882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
217982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
218082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
218182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
218282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
218382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
218482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
218582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
218682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
218782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
218882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
218982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
219082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
219182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
219282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
219382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
219782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
219882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
219982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
220182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
220282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
220782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2219ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) {
2220e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        if (mValidator == null) {
2221e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira            return;
2222e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira        }
2223ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        for (final String email : to) {
222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
222782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
222982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
223082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
223182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
223282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
223382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
223582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
223682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
223782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
223982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
224182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
224282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
224382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
224482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
22450bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                            @Override
224682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
224782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
224882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
225482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
225582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
225682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
225782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
225882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
225982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
226082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
226182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
226282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
2263eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
226482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
226582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
226682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
226782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
226982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
227082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
227182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
227282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
22737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
227482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
227582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
227682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
227782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
2278a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira            // AND there is actually something in the draft to save.
2279d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang            return (mTextChanged || mAttachmentsChanged || mReplyFromChanged)
2280a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira                    && !isBlank();
228182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
228282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
228382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
228482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2285bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
228682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
228782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
228882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
228982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
2290bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
2291bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
2292bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
2293bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
2294bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
2295bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2296bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2297bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
2298bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
2299bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
2300bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2301bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
2302bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
2303bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2304bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2305bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
2306bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
2307bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
2308bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
2309bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2310bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
2311bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
2312bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
2313bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
2314bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
2315bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
2316bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
2317bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
2318bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2319bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
232082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
232182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
232282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
232382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
232482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
232582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
232682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
232782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
2328eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
232982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
233033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
233133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
233282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
2333181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
2334181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
2335181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
2336181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
2337181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2338181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
2339dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            final boolean orientationChanged, final boolean autoSend) {
2340009b3712ff1657fa839049826451321fdd938d32Mark Wei        if (mAccounts == null || mAccount == null) {
2341009b3712ff1657fa839049826451321fdd938d32Mark Wei            Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show();
2342dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            if (autoSend) {
2343dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei                finish();
2344dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei            }
2345009b3712ff1657fa839049826451321fdd938d32Mark Wei            return false;
2346009b3712ff1657fa839049826451321fdd938d32Mark Wei        }
2347009b3712ff1657fa839049826451321fdd938d32Mark Wei
2348ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final String[] to, cc, bcc;
2349ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        final Editable body = mBodyView.getEditableText();
2350181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
2351181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
2352181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
2353181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
2354181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
2355181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
2356181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2357181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2358181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
2359181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
2360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
2361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
2362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2363181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2364181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2365181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
2366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
2368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
2369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
2370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
2373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
2378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2379181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23810bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
2382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
2383ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy                sendOrSave(mBodyView.getEditableText(), save, showToast);
2384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
2397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
2399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
2403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
2407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
2408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
2409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
2412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
2413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
2414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
2415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2418ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy        sendOrSave(body, save, showToast);
2419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
2420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
2424181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
24255c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
2426181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
2427181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2428181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
2429181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
2430181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2431181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2432181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2433181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
2434181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
2436181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
2438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
2439181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2440181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2441181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
2442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
2443181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
2444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
2445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2446181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
2447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
2448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
2449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
24506edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .setNegativeButton(R.string.cancel, this)
24516edd597b1a6628660284f03442cce1f193af66dcMindy Pereira                .show();
2452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
2456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
2457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
2458181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2459181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
2460181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
2461181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2462181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
2465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
2466181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
2467181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
2470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
2471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
2472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2474181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
2475e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
247605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
247744a6339dd80f4b5b9e5d54567021698d92467c5emindyp            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode,
247844a6339dd80f4b5b9e5d54567021698d92467c5emindyp            ReplyFromAccount draftAccount) {
2479b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final ContentValues values = new ContentValues();
248029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
2481b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
2482c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
2483e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
2484e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
2485e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
248629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
24878960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        MessageModification.putCustomFromAddress(values, message.getFrom());
248892551d057965689f1952faeb06763f0762bc717fMindy Pereira
2489e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
2490b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        // Make sure to remove only the composing spans from the Spannable before saving.
2491b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final String htmlBody = Html.toHtml(removeComposingSpans(body));
249205b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
249329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
249429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
249529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
2496e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
2497e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
2498e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
2499e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
250055271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
250155271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
250255271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
250312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
2504e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
250529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
2506e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
2507e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
2508e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
2509e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
251029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
251129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
2512002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = getDraftType(composeMode);
251312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
2514c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
2515c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
2516c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
2517c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2518c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
2519c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                MessageModification.putBody(values,
2520c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                        Utils.convertHtmlToPlainText(fullBody.toString()).toString());
2521c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
2522c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
2523c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
2524c59dd8270215f97d39697dae9e69976bcfe3642bmindyp            MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString())
2525c59dd8270215f97d39697dae9e69976bcfe3642bmindyp                    .toString());
2526c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
2527e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
252812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
252912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
253012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
25313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount,
25323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook                values, refMessageId, message.getAttachments(), save);
253344a6339dd80f4b5b9e5d54567021698d92467c5emindyp        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback,
253444a6339dd80f4b5b9e5d54567021698d92467c5emindyp                draftAccount);
253582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2536181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
2537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
2539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
254082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2541181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
2542181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
254382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2544b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    /**
2545b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * Removes any composing spans from the specified string.  This will create a new
2546b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     * SpannableString instance, as to not modify the behavior of the EditText view.
2547b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook     */
2548b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    private static SpannableString removeComposingSpans(Spanned body) {
2549b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        final SpannableString messageBody = new SpannableString(body);
2550b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        BaseInputConnection.removeComposingSpans(messageBody);
2551b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook        return messageBody;
2552b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook    }
2553b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook
2554002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    private static int getDraftType(int mode) {
2555002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        int draftType = -1;
2556002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        switch (mode) {
2557002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.COMPOSE:
2558002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.COMPOSE;
2559002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2560002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY:
2561002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY;
2562002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2563002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.REPLY_ALL:
2564002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.REPLY_ALL;
2565002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2566002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira            case ComposeActivity.FORWARD:
2567002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                draftType = DraftType.FORWARD;
2568002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira                break;
2569002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        }
2570002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira        return draftType;
2571002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira    }
2572002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira
2573ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy    private void sendOrSave(final Spanned body, final boolean save, final boolean showToast) {
2574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
2575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
25763ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
2577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
2578181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
257982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2580181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
25811f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang            // FIXME: unused
258282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
258382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
25840bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
258582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
2586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
2587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
2588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
2589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
2590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
2592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
2593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
2595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
2597181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
2598181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
260082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26010bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
26037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
2604181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
260544a6339dd80f4b5b9e5d54567021698d92467c5emindyp                    mDraftAccount = sendOrSaveMessage.mAccount;
2606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
2607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
26087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
26097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
26107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
2611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
2612181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
2613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
26157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
2616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
2617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
261882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26190bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
26217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
26227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
26237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
262582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26260bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
26277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
262847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                // Update the last sent from account.
262947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                if (mAccount != null) {
263047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                    MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString());
263147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira                }
26327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
26337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
26347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
26357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
26367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
26377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
26387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
26397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
26407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
26417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
264282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
26447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
26457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
26467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
26477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
26487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
264982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
26507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
26517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
26527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
26537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
26557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
26567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
26577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
2658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
2659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2660181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
266192551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
2662181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
2663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
2664181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
2665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
266692551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
2667181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
2668181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2669181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2670181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
2671181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
2672181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
2673181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2674181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
2675181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2676181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2677e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
267805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
267905b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
268044a6339dd80f4b5b9e5d54567021698d92467c5emindyp                mSendSaveTaskHandler, save, mComposeMode, mDraftAccount);
2681181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2682181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
2683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
2684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2685b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
2686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
2688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
2689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
2690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
2691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
2692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
2693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
2696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
2697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
2698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
2699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
271482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
27152db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira    private void doAttach(String type) {
2716013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2717013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2718d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
27192db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira        i.setType(type);
2720013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2723013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2724013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2725ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2726a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2727ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2728cd0b0b950efebfc3964334067747b97e61c4f027mindyp            mCcBccButton.setVisibility(View.INVISIBLE);
2729ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2730ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2731ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2733326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2734a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2735326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2736326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2737326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2738326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2739326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2740326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2741326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2742cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        clearChangeListeners();
2743a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2744154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
274568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
27460aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                setFieldsFromRefMessage(mComposeMode);
27478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2748ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showCc = false;
2749ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            boolean showBcc = false;
2750ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            if (mDraft != null) {
2751ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Following desktop behavior, if the user has added a BCC
2752ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // field to a draft, we show it regardless of compose mode.
27538960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showBcc = !TextUtils.isEmpty(mDraft.getBcc());
2754ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // Use the draft to determine what to populate.
2755ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira                // If the Bcc field is showing, show the Cc field whether it is populated or not.
27568960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                showCc = showBcc
27578960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy                        || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL);
275868c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            }
275968c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp            if (mRefMessage != null) {
27609b1ac57b10316cc1416c46f04811c54830e01529mindyp                showCc = !TextUtils.isEmpty(mCc.getText());
276168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp                showBcc = !TextUtils.isEmpty(mBcc.getText());
2762ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            }
2763ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira            mCcBccView.show(false, showCc, showBcc);
2764a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2765ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira        updateHideOrShowCcBcc();
2766cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira        initChangeListeners();
2767326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2768326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2769326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2770b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    @VisibleForTesting
2771b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira    protected void resetMessageForModeChange() {
2772154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2773154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2774154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2775154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2776154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2777154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2778154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2779154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2780154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2781154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2782154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2783154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2784154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2785154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2786154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2787154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2788154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2789154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2790154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2791154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2792154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2793154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2794326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2795326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2796326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2797326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2798326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2799326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2800326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2801326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2802326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2803326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2804326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2805326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2806326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2807326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2808326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2809326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2810326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2811326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2812326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2813326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2814326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2815326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2816326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2817326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2818326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
281946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
282046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
282146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
282246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
282340882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(false);
28241623f9bfde8ced840a52820da28a0939bcaa32f9mindyp        mRespondedInline = true;
282509dd373fae26156a847bb99d88474a7538b9e7c1mindyp        if (!mBodyView.hasFocus()) {
28268654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp            mBodyView.requestFocus();
282709dd373fae26156a847bb99d88474a7538b9e7c1mindyp        }
282846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
282946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
283046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
283146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
283246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
283346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
283446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
283546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
283646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
283746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2838eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
283946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
284046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
284146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
284246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
284346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
284446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
284546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
284646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
284746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2848bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
284946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
285046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
285146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
285246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2853eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2854bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2855bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2856bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2857bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2858bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2859bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2860b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2861433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
28622708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString());
28632708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp        if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) {
2864b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
28652708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp            if (!TextUtils.isEmpty(mSignature)) {
2866b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2867b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2868b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2869b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2870b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2871433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2872433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2873433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2874bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2875bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2876bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2877bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2878bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2879bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2880bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2881bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2882bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
288346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
28841a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
28855a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
28865a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
288792551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
288892551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2889f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            // Clear a signature, if there was one.
2890f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.removeTextChangedListener(this);
2891f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String oldSignature = mSignature;
2892f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            String bodyText = getBody().getText().toString();
2893f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            if (!TextUtils.isEmpty(oldSignature)) {
2894f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                int pos = getSignatureStartPosition(oldSignature, bodyText);
2895f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                if (pos > -1) {
2896f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                    mBodyView.setText(bodyText.substring(0, pos));
2897f432dbce53a73eabed150b35033f2ec1a70c9725mindyp                }
2898f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            }
2899b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2900f432dbce53a73eabed150b35033f2ec1a70c9725mindyp            mBodyView.addTextChangedListener(this);
2901181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2902181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2903181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2904181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2905181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2906181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2907181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2908181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
290982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
29101a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
291182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
291282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
291382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
291482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
291582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
291682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
291782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
291882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
291982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
292082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
292182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
292282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
292382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
292482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
292582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
292682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
292782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
292882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
292982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
293082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
293182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
293282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
293382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
293482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
293582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
293682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
293782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
293882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
293982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
294082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
294182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
294282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
294382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2944efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2945efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2946efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2947efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2948efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2949efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
295082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
295182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
295282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
295382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
295482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
295582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
295682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
295782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
29587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
295982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
296082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2961b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
296278ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank                if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) {
2963cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2964cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
29650bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
2966cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
296782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
296882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
296982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
297082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
297182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
297282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
297382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
297482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
297582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
297682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
297782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
297882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
297982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
298082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
298182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
298282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
298382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
298482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2985eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
2986eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2987eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2988eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2989eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2990eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2991eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2992eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2993eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
299448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira            doSave(!mAddingAttachment /* show toast */);
2995eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2996eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2997eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2998eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
2999eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
3000eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
300140882430c874ff29890ec6fa31f7649788cbc470mindyp        // If we are showing any attachments, make sure we have an upper
300240882430c874ff29890ec6fa31f7649788cbc470mindyp        // divider.
300340882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
3004eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
3005eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
300675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
300740882430c874ff29890ec6fa31f7649788cbc470mindyp    @Override
300840882430c874ff29890ec6fa31f7649788cbc470mindyp    public void onAttachmentAdded() {
300940882430c874ff29890ec6fa31f7649788cbc470mindyp        mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0);
301040882430c874ff29890ec6fa31f7649788cbc470mindyp        mAttachmentsView.focusLastAttachment();
301140882430c874ff29890ec6fa31f7649788cbc470mindyp    }
301275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
301375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
301475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
301575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
30160bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
301775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
301875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
301975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
302075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
302175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
302275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
302375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
302475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
302575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
302675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
30270bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
302875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
302975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
303075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
303175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
303275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
303375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
303475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
303575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
303675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
303775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
303875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
303975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
304075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
304175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
304275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
304375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
304475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
304575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
304675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
304775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
304875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
304975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
305075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
305175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
305275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
305375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
305475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
305575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
305675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
305775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
305875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
305975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
306075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
306175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
306275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
306375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
306475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
306575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
306675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
306775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
306875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
306975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
307075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
307175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
307275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
307375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
307475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
307575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
307675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
307775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
307875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
307975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
308075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
308175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
308275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
308375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
308475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
308575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
308675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
308775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
308875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
308975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
309075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
309175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
309275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
309375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
309475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
309575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
309675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
309775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
309875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
309975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
310075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
310175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
310275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
310375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
310475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
310575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
310675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
3107e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira
3108e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) {
3109e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        if (sTestSendOrSaveCallback != null && testCallback != null) {
3110e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira            throw new IllegalStateException("Attempting to register more than one test callback");
3111e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        }
3112e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira        sTestSendOrSaveCallback = testCallback;
3113e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira    }
3114bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira
3115bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    @VisibleForTesting
3116bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    protected ArrayList<Attachment> getAttachments() {
3117bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira        return mAttachmentsView.getAttachments();
3118bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira    }
311996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
312096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
312196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
312296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        switch (id) {
3123a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3124a990a715012379451344246c5156d29938f12886Alice Yang                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
3125a990a715012379451344246c5156d29938f12886Alice Yang                        null, null);
312696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira            case REFERENCE_MESSAGE_LOADER:
312796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null,
312896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                        null, null);
3129b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3130b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                return new CursorLoader(this, MailAppProvider.getAccountsUri(),
3131b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        UIProvider.ACCOUNTS_PROJECTION, null, null, null);
313296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
313396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        return null;
313496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
313596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
313696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
313796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
3138b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        int id = loader.getId();
3139b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        switch (id) {
3140a990a715012379451344246c5156d29938f12886Alice Yang            case INIT_DRAFT_USING_REFERENCE_MESSAGE:
3141b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3142b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    mRefMessage = new Message(data);
3143b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Intent intent = getIntent();
3144a990a715012379451344246c5156d29938f12886Alice Yang                    initFromRefMessage(mComposeMode);
3145a990a715012379451344246c5156d29938f12886Alice Yang                    finishSetup(mComposeMode, intent, null);
3146a990a715012379451344246c5156d29938f12886Alice Yang                    if (mComposeMode != FORWARD) {
3147b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        String to = intent.getStringExtra(EXTRA_TO);
3148b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        if (!TextUtils.isEmpty(to)) {
31490aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setTo(null);
31500aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy                            mRefMessage.setFrom(null);
3151b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            clearChangeListeners();
3152b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            mTo.append(to);
3153b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initChangeListeners();
3154b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3155b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3156b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                } else {
3157b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    finish();
315896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira                }
3159b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3160a990a715012379451344246c5156d29938f12886Alice Yang            case REFERENCE_MESSAGE_LOADER:
3161a990a715012379451344246c5156d29938f12886Alice Yang                // Only populate mRefMessage and leave other fields untouched.
3162a990a715012379451344246c5156d29938f12886Alice Yang                if (data != null && data.moveToFirst()) {
3163a990a715012379451344246c5156d29938f12886Alice Yang                    mRefMessage = new Message(data);
3164a990a715012379451344246c5156d29938f12886Alice Yang                }
3165a990a715012379451344246c5156d29938f12886Alice Yang                finishSetup(mComposeMode, getIntent(), mSavedInstanceState);
3166a990a715012379451344246c5156d29938f12886Alice Yang                break;
3167b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            case LOADER_ACCOUNT_CURSOR:
3168b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                if (data != null && data.moveToFirst()) {
3169b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    // there are accounts now!
3170b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    Account account;
3171faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> accounts = new ArrayList<Account>();
3172faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                    final ArrayList<Account> initializedAccounts = new ArrayList<Account>();
3173b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    do {
3174b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = new Account(data);
3175dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook                        if (account.isAccountReady()) {
3176b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                            initializedAccounts.add(account);
3177b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        }
3178b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        accounts.add(account);
3179b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } while (data.moveToNext());
3180b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    if (initializedAccounts.size() > 0) {
3181b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.wait).setVisibility(View.GONE);
3182b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR);
3183b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        findViewById(R.id.compose).setVisibility(View.VISIBLE);
3184faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                        mAccounts = initializedAccounts.toArray(
3185faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook                                new Account[initializedAccounts.size()]);
3186faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook
3187b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        finishCreate();
3188b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        invalidateOptionsMenu();
3189b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    } else {
3190b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        // Show "waiting"
3191b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        account = accounts.size() > 0 ? accounts.get(0) : null;
3192b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                        showWaitFragment(account);
3193b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    }
3194b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                }
3195b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                break;
3196b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        }
3197b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3198b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3199b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private void showWaitFragment(Account account) {
3200b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        WaitFragment fragment = getWaitFragment();
3201b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        if (fragment != null) {
3202b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            fragment.updateAccount(account);
320396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        } else {
3204b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            findViewById(R.id.wait).setVisibility(View.VISIBLE);
3205b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira            replaceFragment(WaitFragment.newInstance(account, true),
3206b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira                    FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT);
320796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        }
320896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
320996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira
3210b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private WaitFragment getWaitFragment() {
3211b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT);
3212b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3213b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
3214b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    private int replaceFragment(Fragment fragment, int transition, String tag) {
3215b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
3216b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.setTransition(transition);
3217b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        fragmentTransaction.replace(R.id.wait, fragment, tag);
3218b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        final int transactionId = fragmentTransaction.commitAllowingStateLoss();
3219b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira        return transactionId;
3220b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira    }
3221b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira
322296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    @Override
322396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    public void onLoaderReset(Loader<Cursor> arg0) {
322496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira        // Do nothing.
322596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira    }
322683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook
322783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    @Override
322883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    public Context getActivityContext() {
322983e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook        return this;
323083e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook    }
32311f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang}
3232