ComposeActivity.java revision 91906814d08fe6bcfcd97f25f5a01d36d9d5dc73
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/**
28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc.
38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License.
68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at
78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software
118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and
148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License.
158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */
168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose;
188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener;
215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
2682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
2882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
338e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
3482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
3582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
36f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable;
3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
3846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
3982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
41c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
4346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
44c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
45326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
46b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
47b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
48b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
498e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
508e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
515c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup;
52eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection;
53326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
55433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
561f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView;
576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
58013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
597b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
60c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView;
625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R;
63eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener;
649932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
655a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
6630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
6733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
6830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
703ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
7182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
7292551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
73181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
7430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
753ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities;
7612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
7792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
8046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
8182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
838e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
8462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException;
8562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
8846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
89bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
9046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
9175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
9246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
9346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
941c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
95bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
9682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
9746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
9846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
995a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
100b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        AttachmentDeletedListener, OnAccountChangedListener {
1016349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
10236bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int COMPOSE = -1;
10336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int REPLY = 0;
10436bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int REPLY_ALL = 1;
10536bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int FORWARD = 2;
10636bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    static final int EDIT_DRAFT = 3;
1076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
10936bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_ACTION = "action";
1106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
111a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private static final String EXTRA_SHOW_CC_BCC = "showCcBcc";
112a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String UTF8_ENCODING_NAME = "UTF-8";
1148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String MAIL_TO = "mailto";
1168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_SUBJECT = "subject";
1188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BODY = "body";
1208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1219a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira    private static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString";
1229a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
1238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
13182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
13282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
14382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
14482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Key used to store the above map
14582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids";
1466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
1526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
154f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    static final String EXTRA_ATTACHMENTS = "attachments";
155f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1563ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
15736bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
158bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // If this is an action to edit an existing draft messagge, this extra will hold the
159bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
160bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
162013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final String LOG_TAG = new LogUtils().getLogTag();
163013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
164013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
165013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
1678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Max size for attachments (5 megs). Will be overridden by account settings if found.
1708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp): read this from account settings?
1718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
172e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount";
173e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_REQUEST_ID = "requestId";
174e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart";
175e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_FOCUS_SELECTION_END = null;
176e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private static final String EXTRA_MESSAGE = "extraMessage";
1778e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
17982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
18182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
182c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
183c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
184c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
1858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
1868e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
1877b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
18833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
18992551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
190181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
19182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
1926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
1936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
194326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
195326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
19646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
19746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
19846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
199433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
2001a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
2012eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
202eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
2035a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    private FromAddressSpinner mFromSpinner;
204013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
205eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
20682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
20782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
20882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
20982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
21082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
211eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
2123ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private Message mRefMessage;
2137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
2157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
2161f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    private ImageView mAttachmentsButton;
2173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
218326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
219326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
220326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
222bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        launch(launcher, account, message, EDIT_DRAFT);
223326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
224326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
22833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launch(launcher, account, null, COMPOSE);
2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
2363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY);
2376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
2433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY_ALL);
2446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2493ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
2503ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, FORWARD);
2516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static void launch(Context launcher, Account account, Message message, int action) {
2546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
2556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
2576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
258bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
259bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
260bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
261bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
262bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
2636349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
2646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2658e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
2678e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
2688e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
2698e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
27046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
271818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
272e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Account account;
273e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message;
274e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int action;
275e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE)) {
276e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE);
277e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT);
278e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE);
279e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE);
280e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
281e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            account = (Account)intent.getParcelableExtra(Utils.EXTRA_ACCOUNT);
282e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
283e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // Initialize the message from the message in the intent
284e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
285e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
286e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
28792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        if (account == null) {
28892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this);
28992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            if (syncingAccounts.length > 0) {
29092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook                account = syncingAccounts[0];
29192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            }
29292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        }
29392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
29492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
295818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
296818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
297818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
299e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (message != null && action != EDIT_DRAFT) {
300e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
301e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
302a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira            showCcBcc(savedInstanceState);
303e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if (action == EDIT_DRAFT) {
304e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initFromDraftMessage(message);
305bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
306bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
307bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
308bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
309bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
310bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
311bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
312bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
313bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
314bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
315bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
316bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
317bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
318bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
319bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
320bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
321e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            initQuotedTextFromRefMessage(mRefMessage, action);
322e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
323e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mRefMessage != null) {
324e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                initFromRefMessage(action, mAccount.name);
325e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
3268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
3278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
328bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
329bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
330bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
331eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
33246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
333818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
334f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        initAttachmentsFromIntent(intent);
3351a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        initActionBar(action);
336e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(),
337e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                action);
33875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
339433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        setFocus(action);
340433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
341433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
342433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
343433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
344433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
345433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
346433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
347433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
348433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
349433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
350433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
351433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
352433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
353433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
354433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
355433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
356433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
357433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
358433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
359433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
360433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mTo.requestFocus();
361433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
362433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
363433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
364433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
365433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
366433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
367433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
368433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
369433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
370433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
371433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
372433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
373433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
374433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
375433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
376433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
377433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
378433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
379433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
380433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
381433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
382433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        } else if (length > 0) {
383433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
384433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
385433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
3861a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
3871a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
3881a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
3891a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
3901a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
3911a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
3921a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
393818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
39462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount);
395818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
3961a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
3971a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
398eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
399eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
400eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
401eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
402eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
403eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
404eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
405eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
406eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
407eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
408eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveIfNeeded();
409eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
410eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
411eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
412eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
413eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAddingAttachment = false;
414eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
415eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) {
416eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
417eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
418eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
419eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
420eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
421e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    public final void onRestoreInstanceState(Bundle savedInstanceState) {
422e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        super.onRestoreInstanceState(savedInstanceState);
423e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (savedInstanceState != null) {
424e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) {
425e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START);
426e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END);
427e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // There should be a focus and it should be an EditText since we
428e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                // only save these extras if these conditions are true.
429e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                EditText focusEditText = (EditText) getCurrentFocus();
430e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                final int length = focusEditText.getText().length();
431e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                if (selectionStart < length && selectionEnd < length) {
432e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    focusEditText.setSelection(selectionStart, selectionEnd);
433e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                }
434e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
435e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
436e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
437e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
438e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    @Override
439eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
440eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
441e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // The framework is happy to save and restore the selection but only if it also saves and
442e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // restores the contents of the edit text. That's a lot of text to put in a bundle so we do
443e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // this manually.
444e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        View focus = getCurrentFocus();
445e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (focus != null && focus instanceof EditText) {
446e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            EditText focusEditText = (EditText) focus;
447e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart());
448e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd());
449e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
4506273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook
4516273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
452151f1ad1613ecac0207144472872440517172b5aPaul Westbrook        final int selectedPos = mFromSpinner.getSelectedItemPosition();
4536273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook        final ReplyFromAccount selectedReplyFromAccount =
454151f1ad1613ecac0207144472872440517172b5aPaul Westbrook                (replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ?
455151f1ad1613ecac0207144472872440517172b5aPaul Westbrook                        replyFromAccounts.get(selectedPos) :
4566273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook                        null;
457e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (selectedReplyFromAccount != null) {
458e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize()
459e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                    .toString());
460e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account);
461e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        } else {
462e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount);
463e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
464eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
465e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) {
466e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // We don't have a draft id, and we have a request id,
467e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            // save the request id.
468e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putInt(EXTRA_REQUEST_ID, mRequestId);
469e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
470e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
471e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // We want to restore the current mode after a pause
472e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        // or rotation.
473e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = getMode();
474e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putInt(EXTRA_ACTION, mode);
475e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
476e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = createMessage(selectedReplyFromAccount, mode);
477e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        state.putParcelable(EXTRA_MESSAGE, message);
478e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
479e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null) {
480e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage);
481e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
482a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira        state.putBoolean(EXTRA_SHOW_CC_BCC, mCcBccView.isVisible());
483e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
484e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
485e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private int getMode() {
486e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        int mode = ComposeActivity.COMPOSE;
487e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ActionBar actionBar = getActionBar();
488e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) {
489e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mode = actionBar.getSelectedNavigationIndex();
490e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
491e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return mode;
492e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
493e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
494e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) {
495e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message message = new Message();
496e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.id = UIProvider.INVALID_MESSAGE_ID;
497e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.serverId =UIProvider.INVALID_MESSAGE_ID;
498e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.uri = null;
499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.conversationUri = null;
500e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.subject = mSubject.getText().toString();
501e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.snippet = null;
50291906814d08fe6bcfcd97f25f5a01d36d9d5dc73Paul Westbrook        message.from = selectedReplyFromAccount != null ?
50391906814d08fe6bcfcd97f25f5a01d36d9d5dc73Paul Westbrook                selectedReplyFromAccount.name : mAccount.name;
504e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.to = mTo.getText().toString();
5054b1377e9f7677671eda0d5508a0603ec7433d19dMindy Pereira        message.cc = mCc.getText().toString();
5064b1377e9f7677671eda0d5508a0603ec7433d19dMindy Pereira        message.bcc = mBcc.getText().toString();
507e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.replyTo = null;
508e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.dateReceivedMs = 0;
509e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        String htmlBody = Html.toHtml(mBodyView.getText());
510e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
511e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyHtml = fullBody.toString();
512e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.bodyText = mBodyView.getText().toString();
513e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.embedsExternalResources = false;
514e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null;
515e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.draftType = mode;
516e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null;
517e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        ArrayList<Attachment> attachments = mAttachmentsView.getAttachments();
518e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.hasAttachments = attachments != null && attachments.size() > 0;
519e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentListUri = null;
520e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.messageFlags = 0;
521e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.saveUri = null;
522e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.sendUri = null;
523e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.alwaysShowImages = false;
524e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.attachmentsJson = Attachment.toJSONArray(attachments);
525e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        CharSequence quotedText = mQuotedTextView.getQuotedText();
526e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView
527e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                .getQuotedTextOffset(quotedText.toString()) : -1;
528e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        message.accountUri = null;
529e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        return message;
530eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
531eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
532818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
533818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
534bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        if (account == null) {
535bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira            return;
536bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira        }
53723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
53823e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
539b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
540b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
54123e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
542818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
543818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
544e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromSpinner(Bundle bundle, int action) {
5459a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        String accountString = null;
546e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) {
54762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
54862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
54962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount);
5509a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira        if (bundle != null) {
5519a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) {
5529a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = ReplyFromAccount.deserialize(mAccount,
5539a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                        bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT));
5549a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) {
5559a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING);
5569a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira                mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString);
5579a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira            }
558e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
559e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mReplyFromAccount == null) {
560e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            if (mDraft != null) {
561e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
562e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            } else if (mRefMessage != null) {
563e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira                mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
564e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            }
56562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
56662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
56762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
56862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    mAccount.name, true, false);
56962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
5709a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
57162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
5729a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira
57362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
574a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
575a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
57662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
57762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
578a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
57962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
580a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
581a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
582a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
583a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
584a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
58546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
58646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
58762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
58862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
58962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
59062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
59162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
59262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
59362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
59462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
59562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
59662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
59762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
59862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
59962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
60062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
60162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
60262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
60362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
60462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
60562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
60662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
60762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
60862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
60962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
61062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
61162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
61262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (false) { //mCachedSettings.forceReplyFromDefault) {
61362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
61462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
61562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // If we aren't explicityly told which account to look for, look at
61662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
61762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
61862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
61962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to)));
62062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc)));
62162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
62262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
62362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
62462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
62562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
62662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
62762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
62862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
62962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
63062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
63162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
63262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
63362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
63462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
63562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
63662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
63762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
63862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
63962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
64062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
64162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
64262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
64362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
64462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        try {
64562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            customFroms = FromAddressSpinner.getAccountSpecificFroms(account);
64662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (customFroms != null) {
64762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                for (ReplyFromAccount entry : customFroms) {
64862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    if (recipientsMap.contains(entry.address)) {
64962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                        matchingReplyFrom = entry;
65062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                        matchingAddressCount++;
65162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    }
65262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
65362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
65462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } catch (JSONException e) {
65562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s",
65662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    account.name);
65762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
65862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
65962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
66062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
66162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
66262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
66362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
66462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getDefaultReplyFromAccount(Account account) {
66562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
66662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (ReplyFromAccount from : replyFromAccounts) {
66762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
66862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
66962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
67062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
67162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, true, false);
67262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
67362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
674e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) {
675e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        String sender = msg.from;
67662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
67762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
67862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
67962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
68062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    mAccount.name, true, false);
68162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
68262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
68362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
68462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
68562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
68662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
68762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
68862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
68962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
69062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
69162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
69246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
693a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
6948e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
6958e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
6968e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
6978e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
6987b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
6991f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment);
7001f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        if (mAttachmentsButton != null) {
7011f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            mAttachmentsButton.setOnClickListener(this);
7021f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        }
703818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
704818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
705818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
70682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
70782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
7086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
70946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
71046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
711433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
7121a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
7132eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
714eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
7155a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
716326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
717326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
71875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
71975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
72075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
72175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
72275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
72375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
72475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this));
72575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this));
72675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this));
72775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
728818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
72975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
73075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
731326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void initActionBar(int action) {
732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mComposeMode = action;
733eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
734326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
735eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
736eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
737326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
738eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
739326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
740326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
741326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
742eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
743eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
744326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            switch (action) {
745326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
746eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
747326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
748326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
749eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
750326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
751326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
752eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
753326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
754326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
7556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
756fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
757fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
758fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
7596349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
7606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
76146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void initFromRefMessage(int action, String recipientAddress) {
7628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
7638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
7648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
7658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
7668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        initRecipientsFromRefMessage(recipientAddress, mRefMessage, action);
768e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        initQuotedTextFromRefMessage(mRefMessage, action);
7698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
7708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
7716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
7728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
773c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
774c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromDraftMessage(Message message) {
776bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message");
777bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
778bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
779bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
780bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
781bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
782bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
783bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
784bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
785bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
7862421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
7872421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
7882421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
7895c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                addAttachmentAndUpdateView(a);
7902421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
7912421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
792bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
793bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
794bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
795bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            mBodyView.setText(Html.fromHtml(message.bodyHtml));
796bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
797bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            mBodyView.setText(message.bodyText);
798bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
799bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
800bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
8018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
8028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
8038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
8048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
8058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
8068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
8078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
8088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
8098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
8108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
8118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
8128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
8138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
8148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
8158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
8168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
8178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
8188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
8190b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
8208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
8218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
8228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
823dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                        addToAddresses(Arrays.asList(TextUtils.split(toText, ",")));
8248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
8258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
8268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
8278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
8308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
8318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
8328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
8348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
8358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
8368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
8388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
8398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
8408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
8438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
8448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
8458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
8488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
8498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
8508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
851dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addToAddresses(Arrays.asList(TextUtils.split(value, ",")));
8528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
853dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null);
8548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
855dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira                    addBccAddresses(Arrays.asList(TextUtils.split(value, ",")));
8568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
8578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
8588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
8598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
8608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
8618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
8628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
8658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
8668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
8678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
8688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
8698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
8708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
8738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
8748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
875e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initFromMessageInIntent(Message message) {
876e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        mTo.append(message.to);
877e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        mCc.append(message.cc);
878e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        mBcc.append(message.bcc);
879e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        mBodyView.setText(message.bodyText);
880e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        mSubject.setText(message.subject);
881e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        List<Attachment> attachments = message.getAttachments();
882e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        for (Attachment a : attachments) {
883e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira            mAttachmentsView.addAttachment(a);
884e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        }
885e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        mQuotedTextView.updateCheckedState(message.appendRefMessageContent);
886e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    }
887e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira
8888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
8898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
8908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO: handle the case where there are spaces in the display name as well as the email
8918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // such as "Guy with spaces <guy+with+spaces@gmail.com>" as they it could be encoded
8928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // ambiguously.
8938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
8958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
8968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
8978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String replacePlus = s.replace("+", "%2B");
8988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME);
8998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
9008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
9028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
9038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
9048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
9058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
9068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
9078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
9088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
9098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
9108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
9118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
9128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
9138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
9148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
9158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
9168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
9178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
9188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
919dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira            addToAddresses(Arrays.asList(TextUtils.split(to, ",")));
9208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
9218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
9228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
9238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
9248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
9258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
9268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
9278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
9298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
9308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
9328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
9338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
9358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
9368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
9388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
9398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
9408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME));
9418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
9428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
9438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
9448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
9458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
9468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
9488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
9498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
9508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME),
9518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
9528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
9538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
9548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
9558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
9568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
9588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
9598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
9603ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void initAttachments(Message refMessage) {
9617a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira        mAttachmentsView.addAttachments(mAccount, refMessage);
962eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
963eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
964f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
96503ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
96603ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
96703ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
96803ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
969f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
970f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
971f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
972f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
973f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
974f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
975f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
976f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
977f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
9785c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size =  mAttachmentsView.addAttachment(mAccount, uri);
979f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
980f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // A toast has already been shown to the user,
981f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // just break out of the loop.
982f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
983f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
984f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
985f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
986f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
987f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) {
988f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
989f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                long size = 0;
990f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                try {
9915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                    size =  mAttachmentsView.addAttachment(mAccount, uri);
992f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                } catch (AttachmentFailureException e) {
993f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    // A toast has already been shown to the user, so just
994f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    // exit.
995f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    LogUtils.e(LOG_TAG, e, "Error adding attachment");
996f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
997f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                totalSize += size;
998f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
999f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1000f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND_MULTIPLE.equals(action)
1001f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    && extras.containsKey(Intent.EXTRA_STREAM)) {
1002f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
1003f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (Parcelable uri : uris) {
1004f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
1005f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
10065c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                        size = mAttachmentsView.addAttachment(mAccount, (Uri) uri);
1007f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
1008f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // A toast has already been shown to the user,
1009f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // just break out of the loop.
1010f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
1011f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
1012f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
1013f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
1014f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1015f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1016f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
1017f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
1018f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
1019f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
1020f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
1021f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
1022f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1023f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1024e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    private void initQuotedTextFromRefMessage(Message refMessage, int action) {
1025e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) {
10269932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
10279932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
102846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
102946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
103046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
1031ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
1032a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        boolean ccVisible = !TextUtils.isEmpty(mCc.getText());
1033a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        boolean bccVisible = !TextUtils.isEmpty(mBcc.getText());
1034a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (ccVisible || bccVisible) {
1035a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            mCcBccView.show(false, ccVisible, bccVisible);
1036a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
1037ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1038ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!mCc.isShown() || !mBcc.isShown()) {
1039ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
1040ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setText(getString(!mCc.isShown() ? R.string.add_cc_label
1041ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1042ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1043ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.GONE);
1044ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1045ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
104646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
104746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1048a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    private void showCcBcc(Bundle state) {
1049a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira        if (state != null && state.containsKey(EXTRA_SHOW_CC_BCC)) {
1050a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira            boolean show = state.getBoolean(EXTRA_SHOW_CC_BCC);
10516faeedffd7513074372ad2a4bfede496ff938e26Mindy Pereira            if (show) {
10526faeedffd7513074372ad2a4bfede496ff938e26Mindy Pereira                mCcBccView.show(false, show, show);
10536faeedffd7513074372ad2a4bfede496ff938e26Mindy Pereira            }
1054a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira        }
1055a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira    }
1056a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira
1057013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
1058013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
1059013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
1060013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
1061013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
10622421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
10632421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
10642421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
10655c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Uri contentUri) {
10665c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri == null) {
10672421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
10682421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
1069013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
10705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri));
10715c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        } catch (AttachmentFailureException e) {
10725c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            // A toast has already been shown to the user, no need to do
10735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            // anything.
10745c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            LogUtils.e(LOG_TAG, e, "Error adding attachment");
10755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
10765c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    }
10775c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang
10785c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public void addAttachmentAndUpdateView(Attachment attachment) {
10795c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        try {
10805c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            long size =  mAttachmentsView.addAttachment(mAccount, attachment);
10819932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
10829932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
10839932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
1084013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
10859932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
10869932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            // A toast has already been shown to the user, no need to do
10879932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            // anything.
10889932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
1089013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1090013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1091013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
10923ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initRecipientsFromRefMessage(String recipientAddress, Message refMessage,
109346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            int action) {
10944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
10954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
10964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
10974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
109833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira        initReplyRecipients(mAccount.name, refMessage, action);
10994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1101818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
11023ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initReplyRecipients(String account, Message refMessage, int action) {
11034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // This is the email address of the current user, i.e. the one composing
11044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the reply.
11054a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira        final String accountEmail = Address.getEmailAddress(account).getAddress();
11063ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String fromAddress = refMessage.from;
11073ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to);
11083ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String replytoAddress = refMessage.replyTo;
1109a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
11104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
11124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
11134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
1114a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
1115a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
11163ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
11173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    new String[0]);
1118a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
1119a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
11204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
11213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
11223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    new String[0]);
1123154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
11244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addRecipients(accountEmail, ccAddresses, sentToAddresses);
11253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            addRecipients(accountEmail, ccAddresses,
11263ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    Utils.splitCommaSeparatedString(refMessage.cc));
11274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
11284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
11294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
11324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
11334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
11368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
11378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
11384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
1140bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
1141bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
1142bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
1143bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
11444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
11454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
11464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
11474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
11484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
11508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
11518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
11528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
11534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
11544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
11554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
11568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
11578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
11588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
11598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
11608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
11618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
11628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
11638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
11648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
11658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
11668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
11678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
11684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
11694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) {
11724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        HashSet<String> hash = new HashSet<String>();
11734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (Rfc822Token[] tokens : list) {
11744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
11754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
11764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
11774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
11784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
11794a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
11824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
11834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
11844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
11864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
11874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
11884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
11894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
11924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
11934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
11944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
11954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
11964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
11974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
11984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addAddressToList(String address, RecipientEditTextView list) {
11994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
12004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
12014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
12024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
12034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
12044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
12054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
12064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
12074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
12084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
12094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
12104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected Collection<String> initToRecipients(String account, String accountEmail,
12113ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            String senderAddress, String replyToAddress, String[] inToAddresses) {
12124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
12134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
12144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
12154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
12164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
12174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
12183ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        if (!TextUtils.isEmpty(replyToAddress)) {
12193ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
12204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
12213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(senderAddress);
12224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
12234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
12244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
12254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
12264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static void addRecipients(String account, Set<String> recipients, String[] addresses) {
12274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String email : addresses) {
12284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            // Do not add this account, or any of the custom froms, to the list
12294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            // of recipients.
12304a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
12314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            if (!account.equalsIgnoreCase(recipientAddress)) {
12324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
12334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
12344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
123546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
123646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
12373ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
12383ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
123946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
124046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
124146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
124246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
124346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
124446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
124546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
124646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
124746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
124846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
124946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
125046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (subject.toLowerCase().startsWith(prefix.toLowerCase())) {
125146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
125246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
125346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
125446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
125546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
125646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
125746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
125846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1259818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1260818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1261818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1262818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1263eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1264eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1265818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1266679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
1267c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
126882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1269679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
127033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
127133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1272c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
127333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1274c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
127582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1276c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
127782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
12788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
12798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
12808e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
12818e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
12828e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
12838e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1284a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
12858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
12868e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1287a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
12888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
12891f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.add_attachment:
12901f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                doAttach();
12911f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
12928e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
12938e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1294b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1295b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1296b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1297b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1298b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1299b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
130082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
130182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
13023ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem helpItem = menu.findItem(R.id.help_info_menu_item);
13033ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
13043ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (helpItem != null) {
13053ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            helpItem.setVisible(mAccount != null
13063ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
13073ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
13083ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        if (sendFeedbackItem != null) {
13093ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira            sendFeedbackItem.setVisible(mAccount != null
13103ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira                    && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
13113ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira        }
1312b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1313b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1314b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1315b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1316ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1317ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1318818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1319ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1320ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1321ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1322ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1323ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1324ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1325ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1326ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1327ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1328ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1329ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
133075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        if (mSave != null) {
133175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mSave.setEnabled(shouldSave());
133275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
1333ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1334ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1335ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1336ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1337b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1338b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
133975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1340b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
13417b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira            case R.id.add_attachment:
1342013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira                doAttach();
13437b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1344ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1345ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1346b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
134733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
1348eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                doSave(true, false);
134933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
135033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
135133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
135275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1353efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1354efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1355efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
13561f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
13571f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
13581f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1359fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1360fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                finish();
1361fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1362fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
1363fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                // TODO: enable context sensitive help
1364498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook                Utils.showHelp(this, mAccount, null);
1365fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1366fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
1367fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                Utils.sendFeedback(this, mAccount);
1368fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
136975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
137075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
137133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1372b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1373b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1374b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1375326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
137633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
137782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        sendOrSaveWithSanityChecks(false, true, false);
137833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
137933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
1380eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void doSave(boolean showToast, boolean resetIME) {
1381eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        sendOrSaveWithSanityChecks(true, showToast, false);
1382eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (resetIME) {
1383eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // Clear the IME composing suggestions from the body.
1384eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            BaseInputConnection.removeComposingSpans(mBodyView.getEditableText());
1385eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
138682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
138782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
138882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ interface SendOrSaveCallback {
138982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
13907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
13917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
139282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
139382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
139482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
139582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ static class SendOrSaveTask implements Runnable {
139682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
139782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final SendOrSaveCallback mSendOrSaveCallback;
139882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
139982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final SendOrSaveMessage mSendOrSaveMessage;
140082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
140182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
140282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                SendOrSaveCallback callback) {
140382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
140482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
140582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
140682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
140782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
140882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
140982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
14107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
141182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
141292551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
14137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
14147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
141582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
141682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
141782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
14187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) {
141982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
142082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
142182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
142282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
142392551d057965689f1952faeb06763f0762bc717fMindy Pereira                    if (selectedAccount.account.expungeMessageUri != null) {
142492551d057965689f1952faeb06763f0762bc717fMindy Pereira                        resolver.update(selectedAccount.account.expungeMessageUri, values, null,
1425eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                                null);
1426cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1427cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1428eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
142982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
143082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
143182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
143282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
143382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
143482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
143582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) {
14367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
143782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mContext.getContentResolver().update(
14387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri),
14397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sendOrSaveMessage.mValues, null, null);
144082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            } else {
14417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                ContentResolver resolver = mContext.getContentResolver();
144292551d057965689f1952faeb06763f0762bc717fMindy Pereira                Uri messageUri = resolver
144392551d057965689f1952faeb06763f0762bc717fMindy Pereira                        .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri
144492551d057965689f1952faeb06763f0762bc717fMindy Pereira                                : selectedAccount.account.sendMessageUri,
144592551d057965689f1952faeb06763f0762bc717fMindy Pereira                                sendOrSaveMessage.mValues);
14467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sendOrSaveMessage.mSave && messageUri != null) {
14477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Cursor messageCursor = resolver.query(messageUri,
14487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            UIProvider.MESSAGE_PROJECTION, null, null, null);
1449ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                    if (messageCursor != null) {
1450ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
1451ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            if (messageCursor.moveToFirst()) {
1452ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // Broadcast notification that a new message has
1453ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // been allocated
1454ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
1455ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                        new Message(messageCursor));
1456ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            }
1457ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        } finally {
1458ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            messageCursor.close();
1459ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
14607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
14617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
146282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
146382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
14647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!sendOrSaveMessage.mSave) {
146582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
14667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
146782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
14687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
146982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
14707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
147182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
147282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
147382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
147482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
147582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
147682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Array of the outstanding send or save tasks.  Access is synchronized
147782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // with the object itself
147882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /* package for testing */
147982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
148082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private int mRequestId;
1481bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String mSignature;
148282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
148382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ static class SendOrSaveMessage {
148492551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
148582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
14863ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
148782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final boolean mSave;
148882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
148982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
149092551d057965689f1952faeb06763f0762bc717fMindy Pereira        public SendOrSaveMessage(ReplyFromAccount account, ContentValues values,
14913ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                String refMessageId, boolean save) {
149282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
149382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
149482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
149582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
149682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
149782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
149882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
149982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
150082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
150182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
150282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
150382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
150482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
150582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
150682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
150782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
150882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
150982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
151082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
151182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
151282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
151382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
151482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
151582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
151682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
151782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
151882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
151982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
152082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
152182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
152282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
152382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
152482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
152582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
152682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
152782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
152882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
152982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
153082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
153182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
153282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
153382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
153482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
153582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
153682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
153782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
153882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
153982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
154082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
154182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
154282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
154382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) {
154482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (String email : to) {
154582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
154682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
154782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
154882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
154982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
155082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
155182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
155282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
155382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
155482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
155582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
155682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
155782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
155882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
155982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
156082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
156182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
156282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
156382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
156482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setCancelable(false)
156582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
156682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
15670bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                            @Override
156882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
156982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
157082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
157182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
157282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
157382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
157482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
157582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
157682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
157782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
157882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
157982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
158082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
158182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
158282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
158382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
158482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
1585eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
158682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
158782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
158882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
158982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
159082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
159182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
159282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
159382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
159482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
15957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
159682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
159782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
159882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
159982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
1600eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return (mTextChanged || mAttachmentsChanged ||
160182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    (mReplyFromChanged && !isBlank()));
160282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
160382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
160482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
160582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1606bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
160782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
160882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
160982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
161082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
1611bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
1612bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
1613bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
1614bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
1615bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
1616bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1617bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1618bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
1619bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
1620bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
1621bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1622bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
1623bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
1624bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1625bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1626bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
1627bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
1628bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
1629bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
1630bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1631bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
1632bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
1633bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
1634bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
1635bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
1636bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
1637bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
1638bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
1639bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1640bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
164182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
164282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
164382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
164482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
164582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
164682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
164782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
164882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
1649eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
165082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
165133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
165233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
165382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1654181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
1655181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
1656181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
1657181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
1658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
1660181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            final boolean orientationChanged) {
1661181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1662181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Editable body = mBodyView.getEditableText();
1663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1664181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1666181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1667181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1668181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1669181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1670181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1671181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1672181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
1673181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
1674181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
1675181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
1676181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1677181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1678181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
1680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1681181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
1682181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
1683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
1684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
1687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
1688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
1689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
1690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
1691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
16950bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
1696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
1697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged);
1698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
1702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
1704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
1705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
1706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
1708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
1709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
1710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
1711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
1713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
1714181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
1715181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
1716181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
1717181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1718181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
1721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
1722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1723181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
1726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
1727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
1728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
1729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1730181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1731181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1732181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        sendOrSave(body, save, showToast, false);
1733181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
1734181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1735181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1736181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1737181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
1738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
17395c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
1740181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
1741181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1742181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
1743181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
1744181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1745181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1746181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1747181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
1748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1749181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
1750181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1751181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
1752181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
1753181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1754181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1755181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
1756181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
1757181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
1758181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
1759181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1760181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
1761181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
1762181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
1763181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
1764181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setNegativeButton(R.string.cancel, this).setCancelable(false).show();
1765181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1766181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1767181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1768181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
1769181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
1770181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
1771181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
1773181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
1774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1775181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1776181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1777181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
1778181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1779181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
1780181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1781181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
1782181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
1783181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
1784181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
1785181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1786181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1787181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
1788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira    static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount,
178905b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            Message message, final Message refMessage, Spanned body, final CharSequence quotedText,
179005b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) {
179129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        ContentValues values = new ContentValues();
179229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
1793c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
1794c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
1795e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putToAddresses(values, message.getToAddresses());
1796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCcAddresses(values, message.getCcAddresses());
1797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putBccAddresses(values, message.getBccAddresses());
179829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
1799e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putCustomFromAddress(values, message.from);
180092551d057965689f1952faeb06763f0762bc717fMindy Pereira
1801e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putSubject(values, message.subject);
180229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        String htmlBody = Html.toHtml(body);
180305b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook
180429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
180529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
180629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
1807e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
1808e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
1809e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
1810e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
181155271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                final int quoteStartPos = fullBody.length() + pos;
181255271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                fullBody.append(text);
181355271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook                MessageModification.putQuoteStartPos(values, quoteStartPos);
181412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
1815e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
181629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
1817e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
1818e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
1819e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
1820e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
182129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
182229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
182312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        int draftType = -1;
182412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        switch (composeMode) {
182512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.COMPOSE:
182612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.COMPOSE;
182712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
182812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.REPLY:
182912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.REPLY;
183012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
183112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.REPLY_ALL:
183212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.REPLY_ALL;
183312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
183412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.FORWARD:
183512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.FORWARD;
183612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
183712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
183812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
1839c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
1840c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
1841c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
1842c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
1843c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
1844c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
1845c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
1846c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
1847c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
1848c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
1849c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
1850e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        MessageModification.putAttachments(values, message.getAttachments());
185112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
185212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
185312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
185482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
185592551d057965689f1952faeb06763f0762bc717fMindy Pereira        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount,
1856181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                values, refMessageId, save);
1857181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback);
185882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1859181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
186082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1861181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
1862181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
1863181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
186482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1865181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
1866181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
186782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1868181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void sendOrSave(Spanned body, boolean save, boolean showToast,
1869181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            boolean orientationChanged) {
1870181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
1871181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
18723ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
1873181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
1874181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1876181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1877181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1878181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1879181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1880181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1881181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1882181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1883181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1885181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
188682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
188782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
18880bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
188982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
1890181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
1891181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
1892181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
1893181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
1894181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
1895181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
1896181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
1897181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1898181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
1899181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1900181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
1901181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
1902181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1903181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
190482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
19050bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
19067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
19077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
1908181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
1909181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
1910181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
19117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
19127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
19137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
1914181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
1915181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
1916181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1917181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
19187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
1919181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1920181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
192182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
19220bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
19237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
19247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
19257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
19267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
19277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
192882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
19290bbc858506c95005f2840fa5dff495a9216d2665Marc Blank            @Override
19307ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
19317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
19327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
19337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
19347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
19357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
19367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
19377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
19387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
19397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
19407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
194182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
19427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
19437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
19447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
19457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
19467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
19477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
194882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
19497ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
19507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
19517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
19527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
19537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
19547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
19557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
19567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
1957181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1958181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1959181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
196092551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
1961181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
1962181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
1963181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
1964181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
196592551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
1966181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
1967181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1968181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1969181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
1970181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
1971181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
1972181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1973181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
1974181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1975181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1976e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira        Message msg = createMessage(mReplyFromAccount, getMode());
197705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body,
197805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook                mQuotedTextView.getQuotedTextIfIncluded(), callback,
197912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                mSendSaveTaskHandler, save, mComposeMode);
1980181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1981181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
1982181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
1983181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1984b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
1985181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1986181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
1987181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
1988181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
1989181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
1990181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
1991181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
1992181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1993181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1994181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
1995181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
1996181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
1997181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
1998181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1999181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
2000181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
2001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
2002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
2003181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
2004181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
2005181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
2006181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
2007181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
2008181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
2009181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
2010181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
2011181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
2012181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
201382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2014013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void doAttach() {
2015013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
2016013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
2017181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (android.provider.Settings.System.getInt(getContentResolver(),
2018181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                UIProvider.getAttachmentTypeSetting(), 0) != 0) {
2019013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            i.setType("*/*");
2020013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        } else {
2021013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            i.setType("image/*");
2022013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
2023013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
2024181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
2025181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
2026013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
2027013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
2028ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
2029a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
2030ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
2031ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            mCcBccButton.setVisibility(View.GONE);
2032ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
2033ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
2034ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
2035326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
2036326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
2037a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
2038326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
2039326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
2040326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
2041326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
2042326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
2043326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
2044326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2045a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
2046154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
20478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (mRefMessage != null) {
20488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromRefMessage(mComposeMode, mAccount.name);
20498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
2050a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
2051326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
2052326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
2053326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2054154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    private void resetMessageForModeChange() {
2055154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
2056154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
2057154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
2058154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
2059154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
2060154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
2061154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
2062154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
2063154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
2064154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
2065154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
2066154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
2067154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2068154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
2069154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
2070154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
2071154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
2072154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
2073154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
2074154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
2075154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
2076154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
2077326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
2078326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2079326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
2080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2081326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
2082326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
2083326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
2084326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2085326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2086326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
2087326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
2088326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
2089326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2090326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
2091326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2092326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2093326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
2094326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
2095326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
2096326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
2097326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
2098326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
2099326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
2100326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
2101326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
210246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
210346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
210446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
210546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
210646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
210746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
210846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
210946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
211046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
211146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
211246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
211346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
211446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
211546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
2116eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
211746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
211846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
211946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
212046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
212146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
212246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
212346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
212446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
212546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
2126bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
212746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
212846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
212946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
213046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
2131eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
2132bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
2133bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
2134bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2135bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2136bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2137bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
2138b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
2139433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
2140b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        if (!TextUtils.equals(newSignature, mSignature)) {
2141b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
2142b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            if (!TextUtils.isEmpty(mSignature)
2143b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                    && getSignatureStartPosition(mSignature,
2144b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                            mBodyView.getText().toString()) < 0) {
2145b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
2146b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
2147b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
2148b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
2149b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
2150433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
2151433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
2152433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
2153bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2154bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
2155bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
2156bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
2157bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
2158bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
2159bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
2160bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
2161bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
216246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
21631a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
21645a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
21655a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
216692551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
216792551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
2168b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
2169b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook
2170181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
2171181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
2172181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
2173181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2174181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2175181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2176181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2177181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
217882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
21791a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
218082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
218182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
218282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
218382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
218482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
218582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
218682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
218782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
218882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
218982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
219082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
219182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
219282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
219382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
219782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
219882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
219982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
220182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
220282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
220782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2213efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2214efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2215efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2216efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2217efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2218efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
221982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
222082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
222182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
222382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
22277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
222982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2230b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
2231cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                if (mAccount.expungeMessageUri != null) {
2232cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2233cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
22340bbc858506c95005f2840fa5dff495a9216d2665Marc Blank                    getContentResolver().delete(mDraft.uri, null, null);
2235cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
223682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
223782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
223982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
224182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
224282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
224382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
224482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
224582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
224682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
224782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
224882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2254eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
2255eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2256eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2257eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2258eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2259eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2261eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2262eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
2263eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            doSave(!mAddingAttachment /* show toast */, true /* reset IME */);
2264eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2265eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2266eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2267eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
2268eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
2269eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
2270eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
2271eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
227275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
227375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
227475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
227575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
227675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
22770bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
227875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
227975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
228075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
228175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
228275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
228375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
228475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
228575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
228675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
228775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
22880bbc858506c95005f2840fa5dff495a9216d2665Marc Blank    @Override
228975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
229075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
229175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
229275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
229375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
229475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
229575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
229675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
229775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
229875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
229975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
230075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
230175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
230275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
230375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
230475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
230575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
230675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
230775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
230875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
230975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
231075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
231175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
231275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
231375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
231475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
231575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
231675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
231775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
231875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
231975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
232075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
232175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
232275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
232375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
232475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
232575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
232675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
232775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
232875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
232975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
233075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
233175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
233275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
233375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
233475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
233575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
233675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
233775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
233875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
233975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
234075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
234175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
234275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
234375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
234475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
234575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
234675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
234775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
234875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
234975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
235075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
235175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
235275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
235375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
235475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
235575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
235675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
235775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
235875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
235975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
236075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
236175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
236275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
236375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
236475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
236575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
236675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
236775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
23688183d4519ac4b576c0af41f787267db6eff2efb1Vikram Aggarwal}
2369