ComposeActivity.java revision 12575866e5526e45eaf773c6c98c93c3a06fe156
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;
2082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
23326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar.OnNavigationListener;
248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.app.Activity;
25181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.app.LoaderManager.LoaderCallbacks;
266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
2782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
29181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.CursorLoader;
3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
32181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.Loader;
3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
368e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
3882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
39f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable;
4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
44c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
47c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport android.view.Gravity;
49326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
50b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
51b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
52b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
538e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
54326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.ViewGroup;
558e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
56eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection;
57326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
591f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView;
606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
61013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
627b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
63c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
64eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener;
659932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
665a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
6730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
6833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
7030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
713ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
7282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
73181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
7430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
7512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
7630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R;
7792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
80c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.ex.chips.RecipientEditTextView;
8146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
8282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
8746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
88bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
8946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
9075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
9146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
9246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
931c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
94bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
9582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
9646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
9746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
985a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
99181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        AttachmentDeletedListener, OnAccountChangedListener, LoaderCallbacks<Cursor> {
1006349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
101bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    static final int COMPOSE = -1;
1026349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    static final int REPLY = 0;
1036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    static final int REPLY_ALL = 1;
1046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    static final int FORWARD = 2;
105bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    static final int EDIT_DRAFT = 3;
1066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
1086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private static final String EXTRA_ACTION = "action";
1096349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String GMAIL_FROM = "gmailfrom";
1158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
12982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
13082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
13182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
13282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Key used to store the above map
14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids";
1436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
151f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    static final String EXTRA_ATTACHMENTS = "attachments";
152f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
1543ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
155bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // If this is an action to edit an existing draft messagge, this extra will hold the
156bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
157bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
159013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final String LOG_TAG = new LogUtils().getLogTag();
160013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
161013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
162013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
163181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private static final int ACCOUNT_SETTINGS_LOADER = 0;
1648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
1658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
1668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Max size for attachments (5 megs). Will be overridden by account settings if found.
1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp): read this from account settings?
1698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
1708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
17382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
17482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
175c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
176c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
177c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
1788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
1798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
1807b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
18133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
182181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
18382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
1846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
1856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
186326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
187326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
18846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
18946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
19046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
191eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private TextView mBodyView;
1921a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
1932eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
194eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
1955a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    private FromAddressSpinner mFromSpinner;
196013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
197eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
19882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
19982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
20082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
20182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
20282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
203eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
2043ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private Message mRefMessage;
2057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
2077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
2081f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    private ImageView mAttachmentsButton;
2093ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
210326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
211326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
212326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2133ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
214bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        launch(launcher, account, message, EDIT_DRAFT);
215326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
216326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2176349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
22033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2216349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launch(launcher, account, null, COMPOSE);
2226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2273ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
2283ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY);
2296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2343ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
2353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY_ALL);
2366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
2423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, FORWARD);
2436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2453ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static void launch(Context launcher, Account account, Message message, int action) {
2466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
250bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
251bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
252bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
253bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
254bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
2556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
2598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
2608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
2618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
26246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
263818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
26492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
26592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        Account account = (Account)intent.getParcelableExtra(Utils.EXTRA_ACCOUNT);
26692227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        if (account == null) {
26792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this);
26892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            if (syncingAccounts.length > 0) {
26992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook                account = syncingAccounts[0];
27092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            }
27192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        }
27292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
27392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
274818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
275818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
276818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
27746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
2783ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
27929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
2808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (mRefMessage != null) {
2818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromRefMessage(action, mAccount.name);
2828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
283bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else if (action == EDIT_DRAFT) {
284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Initialize the message from the message in the intent
285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            final Message message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
287bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            initFromMessage(message);
288bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
289bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
290bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
291bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
292bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
293bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
294bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
295bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
296bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
297bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
299bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
300bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
302bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
303bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
304bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
3058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
3068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
307bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
308bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
309bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
310eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
31146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
312818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
313f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        initAttachmentsFromIntent(intent);
3141a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        initActionBar(action);
3155a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        initFromSpinner();
31675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
3171a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
3181a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
3191a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
3201a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
3211a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
3221a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
3231a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
324818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
325818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            mFromSpinner.asyncInitFromSpinner();
326818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
3271a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
3281a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
329eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
330eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
331eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
332eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
333eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
334eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
335eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
336eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
337eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
338eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
339eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
340eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveIfNeeded();
341eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
342eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
343eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
344eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
345eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAddingAttachment = false;
346eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
347eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) {
348eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
349eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
350eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
351eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
352eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
353eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
354eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
355eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
356eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // onSaveInstanceState is only called if the user might come back to this activity so it is
357eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // not an ideal location to save the draft. However, if we have never saved the draft before
358eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // we have to save it here in order to have an id to save in the bundle.
359eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveIfNeededOnOrientationChanged();
360eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
361eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
362818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
363818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
36423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        assert(account != null);
36523e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
36623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
36723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this);
369818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
370818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
3711a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private void initFromSpinner() {
3725a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner.setCurrentAccount(mAccount);
3735a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner.asyncInitFromSpinner();
374eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        boolean showSpinner = mFromSpinner.getCount() > 1;
375eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // If there is only 1 account, just show that account.
376eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // Otherwise, give the user the ability to choose which account to send
377eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // mail from / save drafts to.
378eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromStatic.setVisibility(
379eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                showSpinner ? View.GONE : View.VISIBLE);
3802eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText.setText(mAccount.name);
381eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper.setVisibility(
382eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                showSpinner ? View.VISIBLE : View.GONE);
38346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
38446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
38546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
386a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
3878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
3888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
3898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
3908e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
3917b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
3921f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment);
3931f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        if (mAttachmentsButton != null) {
3941f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            mAttachmentsButton.setOnClickListener(this);
3951f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        }
396818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
397818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
398818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
39982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
40082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
4016349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
40246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
40346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
404eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView = (TextView) findViewById(R.id.body);
4051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
4062eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
407eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
4085a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
409326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
410326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
41175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
41275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
41375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
41475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
41575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
41675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
41775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this));
41875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this));
41975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this));
42075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
421818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
42275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
42375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
424326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void initActionBar(int action) {
425326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mComposeMode = action;
426eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
427326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
428eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
429eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
430326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
431eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
432326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
433326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
434326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
435eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
436eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
437326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            switch (action) {
438326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
439eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
440326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
441326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
442eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
443326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
444326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
445eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
446326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
447326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
4486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
449fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
450fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
451fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
4526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
4536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
45446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void initFromRefMessage(int action, String recipientAddress) {
4558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
4568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
4578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
4588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
4598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
4608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        initRecipientsFromRefMessage(recipientAddress, mRefMessage, action);
4618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        initBodyFromRefMessage(mRefMessage, action);
4628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
4638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
4646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
4658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
466c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
467c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
468bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void initFromMessage(Message message) {
469bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message");
470bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
471bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
472bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
473bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
474bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
475bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
476bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
477bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
478bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
479bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
480bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
481bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
482bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            mBodyView.setText(Html.fromHtml(message.bodyHtml));
483bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
484bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            mBodyView.setText(message.bodyText);
485bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
486bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
487bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // TODO: load attachments from the previous message
488bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // TODO: set the from address spinner to the right from account
489bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // TODO: initialize quoted text value
490bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
491bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
4928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
4938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
4948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
4958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
4968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
4978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
4988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
4998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
5008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
5018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
5028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
5038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
5058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
5068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
5078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
5088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
5098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
5108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
5118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (!GMAIL_FROM.equals(dataUri.getScheme())) {
5128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
5138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
5148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
5158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        addToAddresses(Arrays.asList(toText.split(",")));
5168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
5178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
5188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
5198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
5208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
5228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
5238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
5248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
5258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
5268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
5278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
5288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
5298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
5308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
5318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
5328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
5338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
5358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
5368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
5378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
5388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
5408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
5418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
5428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
5438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    addToAddresses(Arrays.asList(value.split(",")));
5448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
5458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    addCcAddresses(Arrays.asList(value.split(",")), null);
5468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
5478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    addBccAddresses(Arrays.asList(value.split(",")));
5488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
5498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
5508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
5518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
5528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
5538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
5548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
5558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
5578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
5588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            final String action = intent.getAction();
5598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
5608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
5618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
5628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
5638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // TODO(mindyp): read this from account settings.
5658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            int maxSize = DEFAULT_MAX_ATTACHMENT_SIZE;
5668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            int totalSize = 0;
5678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
5688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Take care of attachments passed in by the extras.
5698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (!mAttachmentsChanged) {
5708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (extras.containsKey(EXTRA_ATTACHMENTS)) {
5718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
5728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    for (String uriString : uris) {
5738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        final Uri uri = Uri.parse(uriString);
5748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        long size;
5758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        try {
5768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            size = mAttachmentsView.addAttachment(mAccount, uri,
5778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                                    false /* doSave */, true /* local file */);
5788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        } catch (AttachmentFailureException e) {
5798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            // A toast has already been shown to the user,
5808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            // just break out of the loop.
5818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
5828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            finish();
5838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            return;
5848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        }
5858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
5868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mAttachmentsChanged = true;
5878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
5888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if ((Intent.ACTION_SEND.equals(action)
5898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        || AUTO_SEND_ACTION.equals(action))
5908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        && extras.containsKey(Intent.EXTRA_STREAM)) {
5918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
5928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    try {
5938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mAttachmentsView.addAttachment(mAccount, uri, true /* doSave */,
5948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                                true /* local file */);
5958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    } catch (AttachmentFailureException e) {
5968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // A toast has already been shown to the user, so just
5978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // exit.
5988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
5998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        finish();
6008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        return;
6018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
6028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
6038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (Intent.ACTION_SEND_MULTIPLE.equals(action)
6058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        && extras.containsKey(Intent.EXTRA_STREAM)) {
6068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
6078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    for (Parcelable uri : uris) {
6088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        try {
6098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            mAttachmentsView.addAttachment(mAccount,
6108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                                    (Uri) uri, false /* doSave */, true /* local file */);
6118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        } catch (AttachmentFailureException e) {
6128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            // A toast has already been shown to the user,
6138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            // just break out of the loop.
6148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            LogUtils.e(LOG_TAG, e, "Error adding attachment");
6158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            finish();
6168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                            return;
6178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        }
6188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
6198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mAttachmentsChanged = true;
6208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
6218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
6228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
6238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
6258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
6268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
6288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
6298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO: handle the case where there are spaces in the display name as well as the email
6308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // such as "Guy with spaces <guy+with+spaces@gmail.com>" as they it could be encoded
6318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // ambiguously.
6328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
6348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
6358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
6368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String replacePlus = s.replace("+", "%2B");
6378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME);
6388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
6398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
6418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
6428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
6438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
6448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
6458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
6468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
6478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
6488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
6498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
6508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
6518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
6528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
6538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
6548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
6558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
6568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
6578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
6588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(to.split(" ,")));
6598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
6608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
6618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
6628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
6638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
6648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
6658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
6668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
6688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
6698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
6718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
6728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
6748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
6758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
6778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
6788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
6798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME));
6808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
6818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
6828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
6838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
6848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
6858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
6878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
6888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
6898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME),
6908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
6918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
6928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
6938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
6948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
6958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
6978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
6988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6993ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void initAttachments(Message refMessage) {
7007a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira        mAttachmentsView.addAttachments(mAccount, refMessage);
701eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
702eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
703f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
704f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final Bundle extras = intent.getExtras();
705f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
706f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
707f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
708f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
709f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
710f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
711f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
712f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
713f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
714f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        size =  mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */,
715f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                                true /* local file */);
716f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
717f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // A toast has already been shown to the user,
718f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // just break out of the loop.
719f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
720f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
721f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
722f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
723f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
724f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) {
725f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
726f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                long size = 0;
727f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                try {
728f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    size =  mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */,
729f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                            true /* local file */);
730f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                } catch (AttachmentFailureException e) {
731f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    // A toast has already been shown to the user, so just
732f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    // exit.
733f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    LogUtils.e(LOG_TAG, e, "Error adding attachment");
734f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
735f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                totalSize += size;
736f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
737f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
738f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND_MULTIPLE.equals(action)
739f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    && extras.containsKey(Intent.EXTRA_STREAM)) {
740f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
741f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (Parcelable uri : uris) {
742f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
743f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
744bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                        size = mAttachmentsView.addAttachment(mAccount, (Uri) uri,
745f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                                false /* doSave */, true /* local file */);
746f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
747f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // A toast has already been shown to the user,
748f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // just break out of the loop.
749f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
750f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
751f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
752f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
753f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
754f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
755f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
756f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
757f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
758f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
759f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
760f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
761f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
762f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
7633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void initBodyFromRefMessage(Message refMessage, int action) {
7649932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        if (action == REPLY || action == REPLY_ALL || action == FORWARD) {
7659932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
7669932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
76746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
76846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
76946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
770ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
771a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        boolean ccVisible = !TextUtils.isEmpty(mCc.getText());
772a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        boolean bccVisible = !TextUtils.isEmpty(mBcc.getText());
773a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (ccVisible || bccVisible) {
774a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            mCcBccView.show(false, ccVisible, bccVisible);
775a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
776ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
777ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!mCc.isShown() || !mBcc.isShown()) {
778ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
779ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setText(getString(!mCc.isShown() ? R.string.add_cc_label
780ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
781ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
782ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.GONE);
783ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
784ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
78546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
78646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
787013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
788013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
789013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
790013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
791013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
792013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Uri uri = data != null ? data.getData() : null;
793013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
794f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            long size =  mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */,
795f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira                    true /* local file */);
7969932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
7979932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
7989932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
799013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
8009932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
8019932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            // A toast has already been shown to the user, no need to do
8029932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            // anything.
8039932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
804013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
805013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
806013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
8073ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initRecipientsFromRefMessage(String recipientAddress, Message refMessage,
80846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            int action) {
8094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
8104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
8114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
8124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
81333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira        initReplyRecipients(mAccount.name, refMessage, action);
8144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
8154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
816818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
8173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initReplyRecipients(String account, Message refMessage, int action) {
8184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // This is the email address of the current user, i.e. the one composing
8194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the reply.
8204a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira        final String accountEmail = Address.getEmailAddress(account).getAddress();
8213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String fromAddress = refMessage.from;
8223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to);
8233ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String replytoAddress = refMessage.replyTo;
824a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
8254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
8264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
8274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
8284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
829a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
830a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
8313ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
8323ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    new String[0]);
833a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
834a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
8354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
8363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
8373ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    new String[0]);
838154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
8394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addRecipients(accountEmail, ccAddresses, sentToAddresses);
8403ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            addRecipients(accountEmail, ccAddresses,
8413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    Utils.splitCommaSeparatedString(refMessage.cc));
8424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
8434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
8444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
8454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
8464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
8474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
8484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
8494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
8504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
8518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
8528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
8534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
8544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
855bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
856bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
857bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
858bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
8594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
8604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
8614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
8624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
8634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
8648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
8658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
8668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
8678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
8684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
8694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
8704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
8718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
8728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
8738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
8748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
8758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
8768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
8778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
8788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
8798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
8808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
8818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
8828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
8834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
8844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
8854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
8864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) {
8874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        HashSet<String> hash = new HashSet<String>();
8884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (Rfc822Token[] tokens : list) {
8894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
8904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
8914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
8924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
8934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
8944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
8954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
8964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
8974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
8984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
8994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
9014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
9024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
9034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
9044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
9074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
9084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
9094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
9104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
9114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addAddressToList(String address, RecipientEditTextView list) {
9144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
9154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
9164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
9184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
9204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
9214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
9224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
9254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected Collection<String> initToRecipients(String account, String accountEmail,
9263ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            String senderAddress, String replyToAddress, String[] inToAddresses) {
9274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
9284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
9294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
9304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
9314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
9324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
9333ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        if (!TextUtils.isEmpty(replyToAddress)) {
9343ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
9354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
9363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(senderAddress);
9374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
9384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
9394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static void addRecipients(String account, Set<String> recipients, String[] addresses) {
9424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String email : addresses) {
9434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            // Do not add this account, or any of the custom froms, to the list
9444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            // of recipients.
9454a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
9464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            if (!account.equalsIgnoreCase(recipientAddress)) {
9474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
9484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
9494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
95046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
95146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
9523ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
9533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
95446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
95546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
95646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
95746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
95846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
95946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
96046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
96146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
96246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
96346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
96446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
96546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (subject.toLowerCase().startsWith(prefix.toLowerCase())) {
96646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
96746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
96846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
96946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
97046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
97146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
97246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
97346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
974818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
975818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
976818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
977818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
978eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
979eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
980818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
981679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
982c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
98382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
984679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
98533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
98633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
987c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
98833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
989c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
99082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
991c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
99282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
9938e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
9948e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
9958e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
9968e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
9978e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
9988e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
999a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
10008e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
10018e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1002a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
10038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
10041f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.add_attachment:
10051f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                doAttach();
10061f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
10078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
10088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1009b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1010b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1011b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1012b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1013b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1014b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
101582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
101682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
1017b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1018b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1019b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1020b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1021ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1022ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1023818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1024ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1025ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1026ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1027ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1028ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1029ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1030ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1031ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1032ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1033ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1034ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
103575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        if (mSave != null) {
103675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mSave.setEnabled(shouldSave());
103775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
1038ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1039ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1040ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1041ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1042b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1043b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
104475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1045b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
10467b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira            case R.id.add_attachment:
1047013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira                doAttach();
10487b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1049ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1050ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1051b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
105233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
1053eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                doSave(true, false);
105433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
105533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
105633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
105775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1058efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1059efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1060efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
10611f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
10621f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
10631f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1064fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1065fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                finish();
1066fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1067fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
1068fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                // TODO: enable context sensitive help
1069fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                Utils.showHelp(this, mAccount.helpIntentUri, null);
1070fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1071fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
1072fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                Utils.sendFeedback(this, mAccount);
1073fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
107475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
107575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
107633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1077b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1078b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1079b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
108133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
108282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        sendOrSaveWithSanityChecks(false, true, false);
108333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
108433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
1085eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void doSave(boolean showToast, boolean resetIME) {
1086eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        sendOrSaveWithSanityChecks(true, showToast, false);
1087eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (resetIME) {
1088eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // Clear the IME composing suggestions from the body.
1089eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            BaseInputConnection.removeComposingSpans(mBodyView.getEditableText());
1090eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
109182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
109282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
109382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ interface SendOrSaveCallback {
109482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
10957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
10967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
109782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
109882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
109982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
110082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ static class SendOrSaveTask implements Runnable {
110182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
110282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final SendOrSaveCallback mSendOrSaveCallback;
110382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
110482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final SendOrSaveMessage mSendOrSaveMessage;
110582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
110682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
110782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                SendOrSaveCallback callback) {
110882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
110982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
111082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
111182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
111282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
111382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
111482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
11157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
111682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
11177ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final Account selectedAccount = sendOrSaveMessage.mSelectedAccount;
11187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
11197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
112082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
112182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
112282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
11237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) {
112482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
112582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
112682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
112782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
1128cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    if (selectedAccount.expungeMessageUri != null) {
1129cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        resolver.update(selectedAccount.expungeMessageUri, values, null,
1130eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                                null);
1131cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1132cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1133eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
113482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
113582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
113682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
113782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
113882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
113982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
114082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) {
11417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
114282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mContext.getContentResolver().update(
11437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri),
11447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sendOrSaveMessage.mValues, null, null);
114582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            } else {
11467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                ContentResolver resolver = mContext.getContentResolver();
11477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                Uri messageUri = resolver.insert(
1148cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        sendOrSaveMessage.mSave ? selectedAccount.saveDraftUri
1149cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                                : selectedAccount.sendMessageUri, sendOrSaveMessage.mValues);
11507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sendOrSaveMessage.mSave && messageUri != null) {
11517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Cursor messageCursor = resolver.query(messageUri,
11527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            UIProvider.MESSAGE_PROJECTION, null, null, null);
1153ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                    if (messageCursor != null) {
1154ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
1155ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            if (messageCursor.moveToFirst()) {
1156ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // Broadcast notification that a new message has
1157ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // been allocated
1158ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
1159ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                        new Message(messageCursor));
1160ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            }
1161ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        } finally {
1162ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            messageCursor.close();
1163ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
11647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
11657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
116682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
116782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
11687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!sendOrSaveMessage.mSave) {
116982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
11707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
117182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
11727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
117382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
11747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
117582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
117682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
117782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
117882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
117982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
118082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Array of the outstanding send or save tasks.  Access is synchronized
118182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // with the object itself
118282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /* package for testing */
118382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
118482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private int mRequestId;
1185bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String mSignature;
118682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
118782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ static class SendOrSaveMessage {
118882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final Account mAccount;
118982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final Account mSelectedAccount;
119082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
11913ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
119282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final boolean mSave;
119382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
119482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
119582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveMessage(Account account, Account selectedAccount, ContentValues values,
11963ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                String refMessageId, boolean save) {
119782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
119882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSelectedAccount = selectedAccount;
119982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
120082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
120182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
120282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
120382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
120482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
120582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
120682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
120782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
120882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
120982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
121082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
121182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
121282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
121382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
121482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
121582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
121682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
121782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
121882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
121982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
122082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
122182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
122282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
122382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
122482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
122582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
122682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
122782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
122882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
122982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
123082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
123182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
123282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
123382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
123482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
123582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
123682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
123782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
123882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
123982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
124082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
124182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
124282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
124382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
124482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
124582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
124682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
124782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
124882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
124982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) {
125082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (String email : to) {
125182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
125282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
125382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
125482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
125582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
125682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
125782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
125882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
125982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
126082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
126182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
126282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
126382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
126482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
126582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
126682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
126782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
126882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
126982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
127082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setCancelable(false)
127182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
127282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
127382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
127482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
127582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
127682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
127782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
127882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
127982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
128082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
128182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
128282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
128382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
128482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
128582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
128682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
128782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
128882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
128982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
1290eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
129182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
129282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
129382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
129482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
129582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
129682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
129782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
129882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
129982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
13007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
130182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
130282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
130382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
130482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
1305eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return (mTextChanged || mAttachmentsChanged ||
130682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    (mReplyFromChanged && !isBlank()));
130782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
130882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
130982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
131082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1311bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
131282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
131382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
131482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
131582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
1316bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
1317bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
1318bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
1319bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
1320bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
1321bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1322bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1323bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
1324bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
1325bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
1326bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1327bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
1328bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
1329bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1330bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1331bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
1332bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
1333bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
1334bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
1335bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1336bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
1337bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
1338bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
1339bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
1340bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
1341bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
1342bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
1343bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
1344bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1345bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
134682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
134782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
134882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
134982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
135082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
135182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
135282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
135382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
1354eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
135582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
135633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
135733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
135882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1359181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
1360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
1361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
1362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
1363181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1364181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
1365181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            final boolean orientationChanged) {
1366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Editable body = mBodyView.getEditableText();
1368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
1378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
1379181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
1380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
1381181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
1385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
1387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
1388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
1389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
1392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
1393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
1394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
1395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
1396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
1400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
1401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged);
1402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
1406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
1408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
1409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
1410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
1412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
1413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
1414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
1415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
1417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
1418181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
1419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
1420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
1421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1424181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
1425181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
1426181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1427181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1428181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1429181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
1430181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
1431181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
1432181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
1433181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1434181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1436181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        sendOrSave(body, save, showToast, false);
1437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
1438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1439181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1440181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1441181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
1442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
1443181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
1445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1446181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
1447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
1448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1450181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1451181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
1452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
1454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
1456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
1457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1458181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1459181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
1460181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
1461181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
1462181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
1463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
1465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
1466181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
1467181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
1468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setNegativeButton(R.string.cancel, this).setCancelable(false).show();
1469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
1473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
1474181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
1475181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1476181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
1477181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
1478181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1479181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1480181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1481181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
1482181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1483181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
1484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
1486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
1487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
1488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
1489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
149229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira    static int sendOrSaveInternal(Context context, final Account account,
149329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            final Account selectedAccount, String fromAddress, final Spanned body,
149429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            final String[] to, final String[] cc, final String[] bcc, final String subject,
149529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            final CharSequence quotedText, final List<Attachment> attachments,
14963ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            final String refMessageId, SendOrSaveCallback callback, Handler handler, boolean save,
149712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            int composeMode) {
149829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        ContentValues values = new ContentValues();
149929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
150029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putToAddresses(values, to);
150129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putCcAddresses(values, cc);
150229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putBccAddresses(values, bcc);
150329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
150429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putSubject(values, subject);
150529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        String htmlBody = Html.toHtml(body);
150629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
150729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
150829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
1509e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
1510e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
1511e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
1512e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
1513e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text.substring(0, pos));
1514e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putQuoteStartPos(values, pos);
151512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
1516e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
151729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
1518e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
1519e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
1520e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
1521e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
152229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
152329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
152412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        int draftType = -1;
152512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        switch (composeMode) {
152612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.COMPOSE:
152712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.COMPOSE;
152812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
152912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.REPLY:
153012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.REPLY;
153112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
153212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.REPLY_ALL:
153312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.REPLY_ALL;
153412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
153512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.FORWARD:
153612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.FORWARD;
153712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
153812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
153912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
154029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
154129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putBodyHtml(values, fullBody.toString());
1542f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        MessageModification.putAttachments(values, attachments);
154312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
154412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
154512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
154682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1547181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(account, selectedAccount,
1548181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                values, refMessageId, save);
1549181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback);
155082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1551181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
155282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
1554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
1555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
155682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
1558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
155982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void sendOrSave(Spanned body, boolean save, boolean showToast,
1561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            boolean orientationChanged) {
1562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
1563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
1564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && ActivityManager.isUserAMonkey()) {
1565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
1566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
156782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
157682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
157882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
157982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
158082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
1581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
1582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
1583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
1584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
1585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
1586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
1587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
1588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
1590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
1592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
1593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
159582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
15967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
15977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
1598181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
1599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
1600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
16017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
16027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
16037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
1604181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
1605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
1606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
16087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
1609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1610181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
161182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
16127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
16137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
16147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
16157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
16167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
161782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
16187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
16197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
16207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
16217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
16227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
16237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
16247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
16257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
16267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
16277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
16287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
162982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
16307ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
16317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
16327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
16337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
16347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
16357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
163682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
16377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
16387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
16397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
16407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
16417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
16427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
16437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
16447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
1645181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1646181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1647181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
1648181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Account selectedAccount = mAccount;
1649181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
1650181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
1651181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
1652181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
1653181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            selectedAccount = mAccount;
1654181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
1655181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1656181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1657181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
1658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
1659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
1660181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1661181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
1662181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
166412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        String refMessageString = mRefMessage != null ? mRefMessage.uri.toString() : "";
1665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mRequestId = sendOrSaveInternal(this, mAccount, selectedAccount, fromAddress, body, to, cc,
1666181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                bcc, mSubject.getText().toString(), mQuotedTextView.getQuotedText(),
166712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                mAttachmentsView.getAttachments(), refMessageString, callback,
166812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                mSendSaveTaskHandler, save, mComposeMode);
1669181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1670181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
1671181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
1672181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1673181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mAccount = selectedAccount;
1674181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1675181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
1676181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
1677181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
1678181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
1679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
1680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
1681181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1682181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
1684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
1685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
1686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
1687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
1689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
1691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
1696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
1697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
1698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
1700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
1701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
170282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1703013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void doAttach() {
1704013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
1705013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
1706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (android.provider.Settings.System.getInt(getContentResolver(),
1707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                UIProvider.getAttachmentTypeSetting(), 0) != 0) {
1708013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            i.setType("*/*");
1709013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        } else {
1710013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            i.setType("image/*");
1711013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1712013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
1713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
1714181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
1715013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1716013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
1717ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
1718a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
1719ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1720ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            mCcBccButton.setVisibility(View.GONE);
1721ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1722ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1723ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1724326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
1725326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
1726a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
1727326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
1728326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
1729326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
1730326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
1731326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
1732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
1733326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1734a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
1735154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
17368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (mRefMessage != null) {
17378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromRefMessage(mComposeMode, mAccount.name);
17388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1739a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
1740326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
1741326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1742326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1743154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    private void resetMessageForModeChange() {
1744154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
1745154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
1746154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
1747154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
1748154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
1749154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
1750154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
1751154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
1752154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
1753154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
1754154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
1755154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
1756154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
1757154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
1758154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
1759154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
1760154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
1761154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
1762154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
1763154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
1764154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
1765154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
1766326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
1767326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1768326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
1769326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1770326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
1771326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
1772326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
1773326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1774326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1775326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
1776326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
1777326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
1778326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1779326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
1780326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1781326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1782326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
1783326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
1784326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
1785326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
1786326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1787326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
1788326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
1789326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1790326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
179146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
179246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
179346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
179446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
179546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
179646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
179746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
179846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
179946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
180046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
180146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
180246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
180346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
180446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
1805eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
180646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
180746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
180846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
180946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
181046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
181146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
181246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
181346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
181446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
1815bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
181646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
181746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
181846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
181946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
1820eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
1821bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
1822bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
1823bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1824bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1825bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1826bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
1827bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        mSignature = mCachedSettings != null ? mCachedSettings.signature : null;
1828bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (!TextUtils.isEmpty(mSignature)) {
1829bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            // Appending a signature does not count as changing text.
1830bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            mBodyView.removeTextChangedListener(this);
1831bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            mBodyView.append(convertToPrintableSignature(mSignature));
1832bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            mBodyView.addTextChangedListener(this);
1833bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1834bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1835bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1836bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
1837bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
1838bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
1839bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
1840bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1841bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
184246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
18431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
18445a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
18455a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
18465a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        Account selectedAccountInfo = mFromSpinner.getCurrentAccount();
1847181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!mAccount.equals(selectedAccountInfo)) {
1848181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mAccount = selectedAccountInfo;
1849181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mCachedSettings = null;
1850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this);
1851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
1852181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
1853181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
1854181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
1855181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
1856181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1857181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
1858181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
185982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
18601a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
186182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
186282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
186382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
186482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
186582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
186682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
186782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
186882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
186982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
187082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
187182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
187282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
187382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
187482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
187682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
187782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
187882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
187982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
188082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
188182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
188282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
188382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
188582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
188682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
188782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
188882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
188982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
189082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
189182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
189282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
189382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1894efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
1895efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
1896efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
1897efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
1898efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
1899efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
190082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
190182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
190282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
190382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
190482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
190582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
190682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
190782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
19087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
190982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
191082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
1911b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
1912cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                if (mAccount.expungeMessageUri != null) {
1913cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
1914cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
1915cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    // TODO(mindyp): call delete on this conversation instead.
1916cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
191782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
191882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
191982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
192082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
192182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
192282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
192382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
192482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
192582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
192682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
192782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
192882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
192982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
193082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
193182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
193282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
193382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
193482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1935eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
1936eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
1937eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
1938eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
1939eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
1940eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
1941eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
1942eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1943eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
1944eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            doSave(!mAddingAttachment /* show toast */, true /* reset IME */);
1945eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
1946eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1947eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1948eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeededOnOrientationChanged() {
1949eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
1950eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
1951eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
1952eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
1953eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
1954eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
1955eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1956eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
1957eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            doSaveOrientationChanged(!mAddingAttachment /* show toast */, true /* reset IME */);
1958eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
1959eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1960eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1961eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    /**
1962eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira     * Save a draft if a draft already exists or the message is not empty.
1963eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira     */
1964eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void doSaveOrientationChanged(boolean showToast, boolean resetIME) {
1965eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveOnOrientationChanged();
1966eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (resetIME) {
1967eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // Clear the IME composing suggestions from the body.
1968eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            BaseInputConnection.removeComposingSpans(mBodyView.getEditableText());
1969eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
1970eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1971eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1972eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected boolean saveOnOrientationChanged() {
1973eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        return sendOrSaveWithSanityChecks(true, false, true);
1974eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1975eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1976eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
1977eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
1978eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
1979eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
1980eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
198175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
198275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
198375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
198475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
198575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
198675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
198775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
198875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
198975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
199075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
199175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
199275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
199375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
199475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
199575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
199675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
199775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
199875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
199975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
200075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
200175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
200275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
200375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
200475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
200575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
200675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
200775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
200875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
200975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
201075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
201175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
201275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
201375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
201475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
201575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
201675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
201775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
201875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
201975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
202075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
202175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
202275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
202375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
202475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
202575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
202675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
202775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
202875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
202975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
203075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
203175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
203275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
203375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
203475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
203575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
203675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
203775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
203875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
203975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
204075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
204175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
204275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
204375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
204475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
204575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
204675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
204775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
204875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
204975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
205075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
205175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
205275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
205375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
205475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
205575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
205675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
205775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
205875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
205975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
206075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
206175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
206275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
206375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
206475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
206575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
206675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
206775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
206875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
206975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
207075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
207175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
207275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
207375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
207475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
2075181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2076181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    @Override
2077181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
2078181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (id == ACCOUNT_SETTINGS_LOADER) {
207923e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            if (mAccount != null && mAccount.settingsQueryUri != null) {
2080181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return new CursorLoader(this, mAccount.settingsQueryUri,
2081181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        UIProvider.SETTINGS_PROJECTION, null, null, null);
2082181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2083181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2084181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return null;
2085181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2086181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2087181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    @Override
2088181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
2089181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (loader.getId() == ACCOUNT_SETTINGS_LOADER) {
2090181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (data != null) {
2091181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                data.moveToFirst();
2092181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                mCachedSettings = new Settings(data);
2093bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                appendSignature();
2094181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2095181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2096181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2097181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2098181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    @Override
2099181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public void onLoaderReset(Loader<Cursor> loader) {
2100181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do nothing.
2101181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
21028e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira}