ComposeActivity.java revision 498e76d7efccc92386fe57c65a2ef8d5a0172604
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/**
28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc.
38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License.
68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at
78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira *
108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software
118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and
148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License.
158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */
168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose;
188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar;
2082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager;
2182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog;
2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog;
23326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar.OnNavigationListener;
248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.app.Activity;
25181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.app.LoaderManager.LoaderCallbacks;
266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver;
2782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues;
286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context;
29181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.CursorLoader;
3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface;
316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent;
32181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.Loader;
3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo;
347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor;
356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri;
368e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle;
3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler;
3882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread;
39f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable;
4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns;
4146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable;
4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html;
4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned;
44c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils;
4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher;
4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token;
47c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
48326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
49b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu;
50b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater;
51b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem;
528e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View;
53326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.ViewGroup;
548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener;
55eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection;
56326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter;
578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button;
58433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText;
591f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView;
606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView;
61013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast;
627b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
63c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator;
64eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener;
659932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException;
665a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener;
6730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener;
6833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
7030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment;
713ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
7282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification;
7392551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount;
74181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings;
7530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
7612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType;
7730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R;
7892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils;
7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
81c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.ex.chips.RecipientEditTextView;
8246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting;
8382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists;
844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets;
858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
8662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException;
8762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException;
898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder;
9046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList;
91bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays;
9246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection;
9375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap;
9446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet;
9546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List;
961c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry;
97bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set;
9882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap;
9946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
10046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener,
1015a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        RespondInlineListener, DialogInterface.OnClickListener, TextWatcher,
102b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        AttachmentDeletedListener, OnAccountChangedListener {
1036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Identifiers for which type of composition this is
104bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    static final int COMPOSE = -1;
1056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    static final int REPLY = 0;
1066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    static final int REPLY_ALL = 1;
1076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    static final int FORWARD = 2;
108bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    static final int EDIT_DRAFT = 3;
1096349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
1106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    // Integer extra holding one of the above compose action
1116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private static final String EXTRA_ACTION = "action";
1126349a043bce28ec999d72635222ae0eb576eb9cdMindy 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
1218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Extra that we can get passed from other activities
1228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_TO = "to";
1238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_CC = "cc";
1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String EXTRA_BCC = "bcc";
1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // List of all the fields
1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC };
1288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
12982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static SendOrSaveCallback sTestSendOrSaveCallback = null;
13082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Map containing information about requests to create new messages, and the id of the
13182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // messages that were the result of those requests.
13282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // This map is used when the activity that initiated the save a of a new message, is killed
13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // before the save has completed (and when we know the id of the newly created message).  When
13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // a save is completed, the service that is running in the background, will update the map
13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    //
13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // When a new ComposeActivity instance is created, it will attempt to use the information in
13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // the previously instantiated map.  If ComposeActivity.onCreate() is called, with a bundle
13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // (restoring data from a previous instance), and the map hasn't been created, we will attempt
14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // to populate the map with data stored in shared preferences.
14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null;
14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Key used to store the above map
14382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids";
1446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
1456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Notifies the {@code Activity} that the caller is an Email
1466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * {@code Activity}, so that the back behavior may be modified accordingly.
1476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     *
1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * @see #onAppUpPressed
1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private static final String EXTRA_FROM_EMAIL_TASK = "fromemail";
1516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
152f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    static final String EXTRA_ATTACHMENTS = "attachments";
153f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
1543ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    //  If this is a reply/forward then this extra will hold the original message
1553ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message";
156bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // If this is an action to edit an existing draft messagge, this extra will hold the
157bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    // draft message
158bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message";
1594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static final String END_TOKEN = ", ";
160013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final String LOG_TAG = new LogUtils().getLogTag();
161013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    // Request numbers for activities we start
162013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_PICK_ATTACHMENT = 1;
163013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private static final int RESULT_CREATE_ACCOUNT = 2;
1648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp) set mime-type for auto send?
1658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND";
1668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
1678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // Max size for attachments (5 megs). Will be overridden by account settings if found.
1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    // TODO(mindyp): read this from account settings?
1698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
1708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * A single thread for running tasks in the background.
17382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
17482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Handler mSendSaveTaskHandler = null;
175c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mTo;
176c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mCc;
177c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    private RecipientEditTextView mBcc;
1788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private Button mCcBccButton;
1798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    private CcBccView mCcBccView;
1807b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira    private AttachmentsView mAttachmentsView;
18133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private Account mAccount;
18292551d057965689f1952faeb06763f0762bc717fMindy Pereira    private ReplyFromAccount mReplyFromAccount;
183181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private Settings mCachedSettings;
18482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private Rfc822Validator mValidator;
1856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    private TextView mSubject;
1866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
187326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ComposeModeAdapter mComposeModeAdapter;
188326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private int mComposeMode = -1;
18946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private boolean mForward;
19046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private String mRecipient;
19146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private QuotedTextView mQuotedTextView;
192433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private EditText mBodyView;
1931a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    private View mFromStatic;
1942eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira    private TextView mFromStaticText;
195eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private View mFromSpinnerWrapper;
1965a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    private FromAddressSpinner mFromSpinner;
197013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    private boolean mAddingAttachment;
198eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private boolean mAttachmentsChanged;
19982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mTextChanged;
20082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean mReplyFromChanged;
20182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSave;
20282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private MenuItem mSend;
20382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private AlertDialog mRecipientErrorDialog;
204eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private AlertDialog mSendConfirmDialog;
2053ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private Message mRefMessage;
2067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private long mDraftId = UIProvider.INVALID_MESSAGE_ID;
2077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Message mDraft;
2087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira    private Object mDraftLock = new Object();
2091f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira    private ImageView mAttachmentsButton;
2103ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
211326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
212326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Can be called from a non-UI thread.
213326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
2143ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void editDraft(Context launcher, Account account, Message message) {
215bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        launch(launcher, account, message, EDIT_DRAFT);
216326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
217326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2206349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
22133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    public static void compose(Context launcher, Account account) {
2226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launch(launcher, account, null, COMPOSE);
2236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2283ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void reply(Context launcher, Account account, Message message) {
2293ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY);
2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void replyAll(Context launcher, Account account, Message message) {
2363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, REPLY_ALL);
2376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    /**
2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     * Can be called from a non-UI thread.
2416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira     */
2423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    public static void forward(Context launcher, Account account, Message message) {
2433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        launch(launcher, account, message, FORWARD);
2446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
2463ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private static void launch(Context launcher, Account account, Message message, int action) {
2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        Intent intent = new Intent(launcher, ComposeActivity.class);
2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_FROM_EMAIL_TASK, true);
2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(EXTRA_ACTION, action);
2506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        intent.putExtra(Utils.EXTRA_ACCOUNT, account);
251bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == EDIT_DRAFT) {
252bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message);
253bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
254bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message);
255bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        launcher.startActivity(intent);
2576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
2588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
2598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
2608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onCreate(Bundle savedInstanceState) {
2618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        super.onCreate(savedInstanceState);
2628e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        setContentView(R.layout.compose);
26346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        findViews();
264818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        Intent intent = getIntent();
26592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
26692227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        Account account = (Account)intent.getParcelableExtra(Utils.EXTRA_ACCOUNT);
26792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        if (account == null) {
26892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this);
26992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            if (syncingAccounts.length > 0) {
27092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook                account = syncingAccounts[0];
27192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook            }
27292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        }
27392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook
27492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook        setAccount(account);
275818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mAccount == null) {
276818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira            return;
277818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
27846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE);
2793ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE);
28029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) {
2818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (mRefMessage != null) {
2828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromRefMessage(action, mAccount.name);
2838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else if (action == EDIT_DRAFT) {
285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Initialize the message from the message in the intent
286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            final Message message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE);
287bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
288bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            initFromMessage(message);
289bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
290bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            // Update the action to the draft type of the previous draft
291bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            switch (message.draftType) {
292bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY:
293bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY;
294bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
295bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.REPLY_ALL:
296bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = REPLY_ALL;
297bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.FORWARD:
299bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = FORWARD;
300bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                case UIProvider.DraftType.COMPOSE:
302bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                default:
303bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    action = COMPOSE;
304bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                    break;
305bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            }
3068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
3078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initFromExtras(intent);
308bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
309bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
310bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (action == COMPOSE) {
311eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mQuotedTextView.setVisibility(View.GONE);
31246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
313818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        initRecipients();
314f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        initAttachmentsFromIntent(intent);
3151a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        initActionBar(action);
316a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        initFromSpinner(action);
31775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        initChangeListeners();
318433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        setFocus(action);
319433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
320433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
321433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    private void setFocus(int action) {
322433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (action == EDIT_DRAFT) {
323433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            int type = mDraft.draftType;
324433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            switch (type) {
325433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.COMPOSE:
326433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.FORWARD:
327433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = COMPOSE;
328433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
329433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY:
330433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                case UIProvider.DraftType.REPLY_ALL:
331433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                default:
332433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    action = REPLY;
333433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                    break;
334433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
335433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
336433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        switch (action) {
337433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case FORWARD:
338433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case COMPOSE:
339433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mTo.requestFocus();
340433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
341433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY:
342433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            case REPLY_ALL:
343433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            default:
344433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
345433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                break;
346433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
347433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    }
348433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
349433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    /**
350433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     * Focus the body of the message.
351433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira     */
352433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira    public void focusBody() {
353433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView.requestFocus();
354433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int length = mBodyView.getText().length();
355433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira
356433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        int signatureStartPos = getSignatureStartPosition(
357433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                mSignature, mBodyView.getText().toString());
358433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        if (signatureStartPos > -1) {
359433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // In case the user deleted the newlines...
360433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(signatureStartPos);
361433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        } else if (length > 0) {
362433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            // Move cursor to the end.
363433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            mBodyView.setSelection(length);
364433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        }
3651a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
3661a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
3671a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    @Override
3681a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    protected void onResume() {
3691a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        super.onResume();
3701a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // Update the from spinner as other accounts
3711a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        // may now be available.
372818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (mFromSpinner != null && mAccount != null) {
37362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount);
374818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        }
3751a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
3761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
377eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
378eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected void onPause() {
379eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onPause();
380eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
381eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mSendConfirmDialog != null) {
382eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mSendConfirmDialog.dismiss();
383eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
384eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mRecipientErrorDialog != null) {
385eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            mRecipientErrorDialog.dismiss();
386eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
387eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
388eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveIfNeeded();
389eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
390eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
391eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
392eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected final void onActivityResult(int request, int result, Intent data) {
393eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAddingAttachment = false;
394eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
395eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) {
396eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            addAttachmentAndUpdateView(data);
397eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
398eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
399eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
400eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
401eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public final void onSaveInstanceState(Bundle state) {
402eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        super.onSaveInstanceState(state);
403eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
404eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // onSaveInstanceState is only called if the user might come back to this activity so it is
405eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // not an ideal location to save the draft. However, if we have never saved the draft before
406eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        // we have to save it here in order to have an id to save in the bundle.
407eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveIfNeededOnOrientationChanged();
408eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
409eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
410818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
411818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    void setAccount(Account account) {
41223e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        assert(account != null);
41323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        if (!account.equals(mAccount)) {
41423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira            mAccount = account;
415b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            mCachedSettings = mAccount.settings;
416b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            appendSignature();
41723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira        }
418818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    }
419818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira
420a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira    private void initFromSpinner(int action) {
42162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (action == EDIT_DRAFT &&
42262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                mDraft.draftType == UIProvider.DraftType.COMPOSE) {
42362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            action = COMPOSE;
42462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
42562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.asyncInitFromSpinner(action, mAccount);
42662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mDraft != null) {
42762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft);
42862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else if (mRefMessage != null) {
42962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage);
43062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
43162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mReplyFromAccount == null) {
43262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
43362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    mAccount.name, true, false);
43462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
43562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        mFromSpinner.setCurrentAccount(mReplyFromAccount);
43662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (mFromSpinner.getCount() > 1) {
437a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // If there is only 1 account, just show that account.
438a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            // Otherwise, give the user the ability to choose which account to
43962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // send mail from / save drafts to.
44062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromStatic.setVisibility(View.GONE);
441a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
44262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            mFromSpinnerWrapper.setVisibility(View.VISIBLE);
443a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        } else {
444a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStatic.setVisibility(View.VISIBLE);
445a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromStaticText.setText(mAccount.name);
446a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira            mFromSpinnerWrapper.setVisibility(View.GONE);
447a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira        }
44846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
44946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
45062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) {
45162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (refMessage.accountUri != null) {
45262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // This must be from combined inbox.
45362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
45462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount from : replyFromAccounts) {
45562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (from.account.uri.equals(refMessage.accountUri)) {
45662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    return from;
45762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
45862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
45962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return null;
46062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
46162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getReplyFromAccount(account, refMessage);
46262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
46362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
46462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
46562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
46662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Given an account and which email address the message was sent to,
46762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * return who the message should be sent from.
46862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param account Account in which the message arrived.
46962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @param sentTo Email address to which the message was sent.
47062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * @return the address from which to reply.
47162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
47262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) {
47362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // First see if we are supposed to use the default address or
47462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // the address it was sentTo.
47562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (false) { //mCachedSettings.forceReplyFromDefault) {
47662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getDefaultReplyFromAccount(account);
47762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
47862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // If we aren't explicityly told which account to look for, look at
47962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // all the message recipients and find one that matches
48062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            // a custom from or account.
48162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            List<String> allRecipients = new ArrayList<String>();
48262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to)));
48362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc)));
48462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            return getMatchingRecipient(account, allRecipients);
48562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
48662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
48762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
48862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    /**
48962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * Compare all the recipients of an email to the current account and all
49062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * custom addresses associated with that account. Return the match if there
49162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     * is one, or the default account if there isn't.
49262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira     */
49362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) {
49462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        // Tokenize the list and place in a hashmap.
49562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount matchingReplyFrom = null;
49662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        Rfc822Token[] tokens;
49762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        HashSet<String> recipientsMap = new HashSet<String>();
49862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (String address : sentTo) {
49962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            tokens = Rfc822Tokenizer.tokenize(address);
50062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (int i = 0; i < tokens.length; i++) {
50162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                recipientsMap.add(tokens[i].getAddress());
50262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
50362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
50462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
50562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        int matchingAddressCount = 0;
50662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> customFroms;
50762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        try {
50862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            customFroms = FromAddressSpinner.getAccountSpecificFroms(account);
50962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (customFroms != null) {
51062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                for (ReplyFromAccount entry : customFroms) {
51162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    if (recipientsMap.contains(entry.address)) {
51262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                        matchingReplyFrom = entry;
51362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                        matchingAddressCount++;
51462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    }
51562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
51662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
51762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } catch (JSONException e) {
51862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s",
51962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    account.name);
52062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
52162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (matchingAddressCount > 1) {
52262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            matchingReplyFrom = getDefaultReplyFromAccount(account);
52362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
52462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return matchingReplyFrom;
52562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
52662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
52762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getDefaultReplyFromAccount(Account account) {
52862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
52962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        for (ReplyFromAccount from : replyFromAccounts) {
53062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            if (from.isDefault) {
53162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                return from;
53262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
53362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
53462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return new ReplyFromAccount(account, account.uri, account.name, account.name, true, false);
53562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
53662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
53762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message draft) {
53862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        String sender = draft.from;
53962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        ReplyFromAccount replyFromAccount = null;
54062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts();
54162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        if (TextUtils.equals(account.name, sender)) {
54262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name,
54362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    mAccount.name, true, false);
54462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        } else {
54562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            for (ReplyFromAccount fromAccount : replyFromAccounts) {
54662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                if (TextUtils.equals(fromAccount.name, sender)) {
54762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    replyFromAccount = fromAccount;
54862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                    break;
54962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira                }
55062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira            }
55162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        }
55262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira        return replyFromAccount;
55362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira    }
55462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira
55546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void findViews() {
556a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccButton = (Button) findViewById(R.id.add_cc_bcc);
5578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        if (mCcBccButton != null) {
5588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira            mCcBccButton.setOnClickListener(this);
5598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
5608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
5617b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira        mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
5621f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment);
5631f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        if (mAttachmentsButton != null) {
5641f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            mAttachmentsButton.setOnClickListener(this);
5651f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira        }
566818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mTo = (RecipientEditTextView) findViewById(R.id.to);
567818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mCc = (RecipientEditTextView) findViewById(R.id.cc);
568818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mBcc = (RecipientEditTextView) findViewById(R.id.bcc);
56982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // TODO: add special chips text change watchers before adding
57082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // this as a text changed watcher to the to, cc, bcc fields.
5716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        mSubject = (TextView) findViewById(R.id.subject);
57246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view);
57346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mQuotedTextView.setRespondInlineListener(this);
574433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        mBodyView = (EditText) findViewById(R.id.body);
5751a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira        mFromStatic = findViewById(R.id.static_from_content);
5762eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira        mFromStaticText = (TextView) findViewById(R.id.from_account_name);
577eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mFromSpinnerWrapper = findViewById(R.id.spinner_from_content);
5785a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira        mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker);
579326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
580326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
58175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Now that the message has been initialized from any existing draft or
58275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // ref message data, set up listeners for any changes that occur to the
58375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // message.
58475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private void initChangeListeners() {
58575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mSubject.addTextChangedListener(this);
58675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBodyView.addTextChangedListener(this);
58775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this));
58875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this));
58975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this));
59075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mFromSpinner.setOnAccountChangedListener(this);
591818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        mAttachmentsView.setAttachmentChangesListener(this);
59275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
59375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
594326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void initActionBar(int action) {
595326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mComposeMode = action;
596eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        ActionBar actionBar = getActionBar();
597326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
598eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
599eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(R.string.compose);
600326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
601eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setTitle(null);
602326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mComposeModeAdapter == null) {
603326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mComposeModeAdapter = new ComposeModeAdapter(this);
604326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
605eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
606eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            actionBar.setListNavigationCallbacks(mComposeModeAdapter, this);
607326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            switch (action) {
608326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY:
609eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(0);
610326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
611326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.REPLY_ALL:
612eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(1);
613326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
614326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                case ComposeActivity.FORWARD:
615eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    actionBar.setSelectedNavigationItem(2);
616326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    break;
617326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
6186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
619fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
620fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
621fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira        actionBar.setHomeButtonEnabled(true);
6226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira    }
6236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira
62446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void initFromRefMessage(int action, String recipientAddress) {
6258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        setSubject(mRefMessage, action);
6268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Setup recipients
6278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == FORWARD) {
6288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mForward = true;
6298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
6308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        initRecipientsFromRefMessage(recipientAddress, mRefMessage, action);
6318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        initBodyFromRefMessage(mRefMessage, action);
6328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (action == ComposeActivity.FORWARD || mAttachmentsChanged) {
6338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            initAttachments(mRefMessage);
6346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira        }
6358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
636c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira    }
637c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira
638bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void initFromMessage(Message message) {
639bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        LogUtils.d(LOG_TAG, "Intializing draft from previous draft message");
640bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
641bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraft = message;
642bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mDraftId = message.id;
643bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mSubject.setText(message.subject);
644bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mForward = message.draftType == UIProvider.DraftType.FORWARD;
645bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        final List<String> toAddresses = Arrays.asList(message.getToAddresses());
646bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addToAddresses(toAddresses);
647bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses);
648bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addBccAddresses(Arrays.asList(message.getBccAddresses()));
6492421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (message.hasAttachments) {
6502421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            List<Attachment> attachments = message.getAttachments();
6512421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            for (Attachment a : attachments) {
6522421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira                addAttachmentAndUpdateView(a.uri);
6532421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            }
6542421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
655bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
656bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // Set the body
657bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        if (!TextUtils.isEmpty(message.bodyHtml)) {
658bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            mBodyView.setText(Html.fromHtml(message.bodyHtml));
659bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        } else {
660bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook            mBodyView.setText(message.bodyText);
661bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        }
662bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
663bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // TODO: load attachments from the previous message
664bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // TODO: set the from address spinner to the right from account
665bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        // TODO: initialize quoted text value
666bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
667bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
6688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
6698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Fill all the widgets with the content found in the Intent Extra, if any.
6708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Also apply the same style to all widgets. Note: if initFromExtras is
6718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * called as a result of switching between reply, reply all, and forward per
6728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * the latest revision of Gmail, and the user has already made changes to
6738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * attachments on a previous incarnation of the message (as a reply, reply
6748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * all, or forward), the original attachments from the message will not be
6758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * re-instantiated. The user's changes will be respected. This follows the
6768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * web gmail interaction.
6778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
6788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromExtras(Intent intent) {
6798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // If we were invoked with a SENDTO intent, the value
6818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // should take precedence
6828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        final Uri dataUri = intent.getData();
6838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (dataUri != null) {
6848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (MAIL_TO.equals(dataUri.getScheme())) {
6858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromMailTo(dataUri.toString());
6868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
6870b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira                if (!mAccount.composeIntentUri.equals(dataUri)) {
6888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    String toText = dataUri.getSchemeSpecificPart();
6898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (toText != null) {
6908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        mTo.setText("");
6918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        addToAddresses(Arrays.asList(toText.split(",")));
6928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
6938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
6948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
6958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
6968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
6978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
6988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
6998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(extraStrings));
7008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC);
7028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
7038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addCcAddresses(Arrays.asList(extraStrings), null);
7048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC);
7068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraStrings != null) {
7078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addBccAddresses(Arrays.asList(extraStrings));
7088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT);
7118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extraString != null) {
7128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            mSubject.setText(extraString);
7138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        for (String extra : ALL_EXTRAS) {
7168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (intent.hasExtra(extra)) {
7178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                String value = intent.getStringExtra(extra);
7188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                if (EXTRA_TO.equals(extra)) {
7198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    addToAddresses(Arrays.asList(value.split(",")));
7208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_CC.equals(extra)) {
7218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    addCcAddresses(Arrays.asList(value.split(",")), null);
7228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BCC.equals(extra)) {
7238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    addBccAddresses(Arrays.asList(value.split(",")));
7248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_SUBJECT.equals(extra)) {
7258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    mSubject.setText(value);
7268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                } else if (EXTRA_BODY.equals(extra)) {
7278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    setBody(value, true /* with signature */);
7288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
7298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
7308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Bundle extras = intent.getExtras();
7338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (extras != null) {
7348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            final String action = intent.getAction();
7358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT);
7368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (text != null) {
7378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(text, true /* with signature */);
7388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
7398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
7428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
7438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    @VisibleForTesting
7458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    protected String decodeEmailInUri(String s) throws UnsupportedEncodingException {
7468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO: handle the case where there are spaces in the display name as well as the email
7478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // such as "Guy with spaces <guy+with+spaces@gmail.com>" as they it could be encoded
7488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // ambiguously.
7498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // Since URLDecode.decode changes + into ' ', and + is a valid
7518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // email character, we need to find/ replace these ourselves before
7528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // decoding.
7538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String replacePlus = s.replace("+", "%2B");
7548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME);
7558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
7568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    /**
7588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * Initialize the compose view from a String representing a mailTo uri.
7598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     * @param mailToString The uri as a string.
7608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira     */
7618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    public void initFromMailTo(String mailToString) {
7628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // We need to disguise this string as a URI in order to parse it
7638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        // TODO:  Remove this hack when http://b/issue?id=1445295 gets fixed
7648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        Uri uri = Uri.parse("foo://" + mailToString);
7658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int index = mailToString.indexOf("?");
7668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        int length = "mailto".length() + 1;
7678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        String to;
7688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        try {
7698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            // Extract the recipient after mailto:
7708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (index == -1) {
7718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length));
7728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
7738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                to = decodeEmailInUri(mailToString.substring(length, index));
7748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
7758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            addToAddresses(Arrays.asList(to.split(" ,")));
7768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } catch (UnsupportedEncodingException e) {
7778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) {
7788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString);
7798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } else {
7808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, e, "Exception  while decoding mailto address");
7818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
7828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
7838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> cc = uri.getQueryParameters("cc");
7858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null);
7868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> otherTo = uri.getQueryParameters("to");
7888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()])));
7898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> bcc = uri.getQueryParameters("bcc");
7918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()])));
7928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
7938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> subject = uri.getQueryParameters("subject");
7948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (subject.size() > 0) {
7958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
7968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME));
7978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
7988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding subject '%s'",
7998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        e.getMessage(), subject);
8008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
8018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        List<String> body = uri.getQueryParameters("body");
8048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (body.size() > 0) {
8058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            try {
8068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME),
8078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        true /* with signature */);
8088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            } catch (UnsupportedEncodingException e) {
8098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body);
8108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
8118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        }
8128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        updateHideOrShowCcBcc();
8148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira    }
8158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira
8163ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void initAttachments(Message refMessage) {
8177a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira        mAttachmentsView.addAttachments(mAccount, refMessage);
818eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
819eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
820f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    private void initAttachmentsFromIntent(Intent intent) {
82103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        Bundle extras = intent.getExtras();
82203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        if (extras == null) {
82303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook            extras = Bundle.EMPTY;
82403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook        }
825f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        final String action = intent.getAction();
826f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        if (!mAttachmentsChanged) {
827f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            long totalSize = 0;
828f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (extras.containsKey(EXTRA_ATTACHMENTS)) {
829f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS);
830f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (String uriString : uris) {
831f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    final Uri uri = Uri.parse(uriString);
832f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
833f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
834f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        size =  mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */,
835f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                                true /* local file */);
836f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
837f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // A toast has already been shown to the user,
838f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // just break out of the loop.
839f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
840f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
841f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
842f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
843f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
844f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) {
845f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
846f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                long size = 0;
847f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                try {
848f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    size =  mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */,
849f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                            true /* local file */);
850f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                } catch (AttachmentFailureException e) {
851f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    // A toast has already been shown to the user, so just
852f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    // exit.
853f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    LogUtils.e(LOG_TAG, e, "Error adding attachment");
854f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
855f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                totalSize += size;
856f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
857f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
858f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (Intent.ACTION_SEND_MULTIPLE.equals(action)
859f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    && extras.containsKey(Intent.EXTRA_STREAM)) {
860f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
861f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                for (Parcelable uri : uris) {
862f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    long size = 0;
863f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    try {
864bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook                        size = mAttachmentsView.addAttachment(mAccount, (Uri) uri,
865f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                                false /* doSave */, true /* local file */);
866f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    } catch (AttachmentFailureException e) {
867f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // A toast has already been shown to the user,
868f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        // just break out of the loop.
869f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                        LogUtils.e(LOG_TAG, e, "Error adding attachment");
870f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    }
871f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                    totalSize += size;
872f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                }
873f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
874f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
875f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            if (totalSize > 0) {
876f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                mAttachmentsChanged = true;
877f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook                updateSaveUi();
878f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook            }
879f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook        }
880f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook    }
881f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
882f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook
8833ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void initBodyFromRefMessage(Message refMessage, int action) {
8849932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        if (action == REPLY || action == REPLY_ALL || action == FORWARD) {
8859932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD);
8869932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        }
88746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
88846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
88946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    private void updateHideOrShowCcBcc() {
890ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        // Its possible there is a menu item OR a button.
891a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        boolean ccVisible = !TextUtils.isEmpty(mCc.getText());
892a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        boolean bccVisible = !TextUtils.isEmpty(mBcc.getText());
893a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (ccVisible || bccVisible) {
894a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            mCcBccView.show(false, ccVisible, bccVisible);
895a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
896ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
897ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!mCc.isShown() || !mBcc.isShown()) {
898ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.VISIBLE);
899ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setText(getString(!mCc.isShown() ? R.string.add_cc_label
900ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
901ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
902ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                mCcBccButton.setVisibility(View.GONE);
903ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
904ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
90546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
90646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
907013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    /**
908013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * Add attachment and update the compose area appropriately.
909013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     * @param data
910013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira     */
911013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void addAttachmentAndUpdateView(Intent data) {
9122421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null);
9132421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    }
9142421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira
9152421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira    public void addAttachmentAndUpdateView(Uri uri) {
9162421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        if (uri == null) {
9172421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            return;
9182421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira        }
919013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        try {
9202421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira            long size =  mAttachmentsView.addAttachment(mAccount, uri,
9212421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira                    false /* doSave */,
922f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira                    true /* local file */);
9239932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            if (size > 0) {
9249932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                mAttachmentsChanged = true;
9259932dee248718d2cec993d93b5115973d1389d0aMindy Pereira                updateSaveUi();
926013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            }
9279932dee248718d2cec993d93b5115973d1389d0aMindy Pereira        } catch (AttachmentFailureException e) {
9289932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            // A toast has already been shown to the user, no need to do
9299932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            // anything.
9309932dee248718d2cec993d93b5115973d1389d0aMindy Pereira            LogUtils.e(LOG_TAG, e, "Error adding attachment");
931013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
932013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
933013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
9343ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initRecipientsFromRefMessage(String recipientAddress, Message refMessage,
93546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            int action) {
9364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Don't populate the address if this is a forward.
9374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (action == ComposeActivity.FORWARD) {
9384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
9394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
94033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira        initReplyRecipients(mAccount.name, refMessage, action);
9414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
943818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    @VisibleForTesting
9443ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    void initReplyRecipients(String account, Message refMessage, int action) {
9454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // This is the email address of the current user, i.e. the one composing
9464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the reply.
9474a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira        final String accountEmail = Address.getEmailAddress(account).getAddress();
9483ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String fromAddress = refMessage.from;
9493ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to);
9503ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String replytoAddress = refMessage.replyTo;
951a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        final Collection<String> toAddresses;
9524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // If this is a reply, the Cc list is empty. If this is a reply-all, the
9544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // Cc list is the union of the To and Cc recipients of the original
9554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, excluding the current user's email address and any addresses
956a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        // already on the To list.
957a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (action == ComposeActivity.REPLY) {
9583ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
9593ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    new String[0]);
960a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            addToAddresses(toAddresses);
961a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        } else if (action == ComposeActivity.REPLY_ALL) {
9624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            final Set<String> ccAddresses = Sets.newHashSet();
9633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress,
9643ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    new String[0]);
965154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            addToAddresses(toAddresses);
9664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addRecipients(accountEmail, ccAddresses, sentToAddresses);
9673ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            addRecipients(accountEmail, ccAddresses,
9683ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                    Utils.splitCommaSeparatedString(refMessage.cc));
9694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addCcAddresses(ccAddresses, toAddresses);
9704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
9714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addToAddresses(Collection<String> addresses) {
9744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        addAddressesToList(addresses, mTo);
9754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) {
9788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        addCcAddressesToList(tokenizeAddressList(addresses),
9798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc);
9804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
9814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
982bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    private void addBccAddresses(Collection<String> addresses) {
983bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        addAddressesToList(addresses, mBcc);
984bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook    }
985bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook
9864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
9874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected void addCcAddressesToList(List<Rfc822Token[]> addresses,
9884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            List<Rfc822Token[]> compareToList, RecipientEditTextView list) {
9894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        String address;
9904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
9918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        if (compareToList == null) {
9928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
9938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
9948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
9954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                    list.append(address + END_TOKEN);
9964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                }
9974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
9988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira        } else {
9998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            HashSet<String> compareTo = convertToHashSet(compareToList);
10008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            for (Rfc822Token[] tokens : addresses) {
10018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                for (int i = 0; i < tokens.length; i++) {
10028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    address = tokens[i].toString();
10038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    // Check if this is a duplicate:
10048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    if (!compareTo.contains(tokens[i].getAddress())) {
10058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        // Get the address here
10068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                        list.append(address + END_TOKEN);
10078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                    }
10088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                }
10098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
10104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
10114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
10124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) {
10144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        HashSet<String> hash = new HashSet<String>();
10154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (Rfc822Token[] tokens : list) {
10164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            for (int i = 0; i < tokens.length; i++) {
10174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                hash.add(tokens[i].getAddress());
10184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
10194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
10204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return hash;
10214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
10224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) {
10244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        @VisibleForTesting
10254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>();
10264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address: addresses) {
10284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            tokenized.add(Rfc822Tokenizer.tokenize(address));
10294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
10304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return tokenized;
10314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
10324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
10344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) {
10354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String address : addresses) {
10364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            addAddressToList(address, list);
10374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
10384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
10394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private void addAddressToList(String address, RecipientEditTextView list) {
10414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        if (address == null || list == null)
10424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            return;
10434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
10454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (int i = 0; i < tokens.length; i++) {
10474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            list.append(tokens[i] + END_TOKEN);
10484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
10494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
10504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    @VisibleForTesting
10524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    protected Collection<String> initToRecipients(String account, String accountEmail,
10533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            String senderAddress, String replyToAddress, String[] inToAddresses) {
10544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // The To recipient is the reply-to address specified in the original
10554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // message, unless it is:
10564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // the current user OR a custom from of the current user, in which case
10574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // it's the To recipient list of the original message.
10584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        // OR missing, in which case use the sender of the original message
10594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        Set<String> toAddresses = Sets.newHashSet();
10603ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        if (!TextUtils.isEmpty(replyToAddress)) {
10613ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(replyToAddress);
10624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        } else {
10633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira            toAddresses.add(senderAddress);
10644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
10654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        return toAddresses;
10664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    }
10674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira
10684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira    private static void addRecipients(String account, Set<String> recipients, String[] addresses) {
10694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        for (String email : addresses) {
10704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            // Do not add this account, or any of the custom froms, to the list
10714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            // of recipients.
10724a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira            final String recipientAddress = Address.getEmailAddress(email).getAddress();
10734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            if (!account.equalsIgnoreCase(recipientAddress)) {
10744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira                recipients.add(email.replace("\"\"", ""));
10754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira            }
10764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira        }
107746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
107846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
10793ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira    private void setSubject(Message refMessage, int action) {
10803ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        String subject = refMessage.subject;
108146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String prefix;
108246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        String correctedSubject = null;
108346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (action == ComposeActivity.COMPOSE) {
108446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = "";
108546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else if (action == ComposeActivity.FORWARD) {
108646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.forward_subject_label);
108746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
108846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            prefix = getString(R.string.reply_subject_label);
108946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
109046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
109146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        // Don't duplicate the prefix
109246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (subject.toLowerCase().startsWith(prefix.toLowerCase())) {
109346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = subject;
109446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
109546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            correctedSubject = String
109646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira                    .format(getString(R.string.formatted_subject), prefix, subject);
109746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
109846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        mSubject.setText(correctedSubject);
109946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
110046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
1101818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void initRecipients() {
1102818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mTo);
1103818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mCc);
1104818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        setupRecipients(mBcc);
1105eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
1106eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
1107818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira    private void setupRecipients(RecipientEditTextView view) {
1108679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook        view.setAdapter(new RecipientAdapter(this, mAccount));
1109c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        view.setTokenizer(new Rfc822Tokenizer());
111082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mValidator == null) {
1111679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook            final String accountName = mAccount.name;
111233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            int offset = accountName.indexOf("@") + 1;
111333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            String account = accountName;
1114c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            if (offset > -1) {
111533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                account = account.substring(accountName.indexOf("@") + 1);
1116c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira            }
111782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValidator = new Rfc822Validator(account);
1118c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira        }
111982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        view.setValidator(mValidator);
11208e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
11218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira
11228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    @Override
11238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    public void onClick(View v) {
11248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        int id = v.getId();
11258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        switch (id) {
1126a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira            case R.id.add_cc_bcc:
11278e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Verify that cc/ bcc aren't showing.
11288e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                // Animate in cc/bcc.
1129a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira                showCcBccViews();
11308e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira                break;
11311f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.add_attachment:
11321f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                doAttach();
11331f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
11348e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira        }
11358e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira    }
1136b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1137b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1138b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onCreateOptionsMenu(Menu menu) {
1139b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        super.onCreateOptionsMenu(menu);
1140b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        MenuInflater inflater = getMenuInflater();
1141b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        inflater.inflate(R.menu.compose_menu, menu);
114282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSave = menu.findItem(R.id.save);
114382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mSend = menu.findItem(R.id.send);
1144b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return true;
1145b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1146b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira
1147b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    @Override
1148ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    public boolean onPrepareOptionsMenu(Menu menu) {
1149ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc);
1150818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira        if (ccBcc != null && mCc != null) {
1151ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            // Its possible there is a menu item OR a button.
1152ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean ccFieldVisible = mCc.isShown();
1153ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            boolean bccFieldVisible = mBcc.isShown();
1154ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            if (!ccFieldVisible || !bccFieldVisible) {
1155ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(true);
1156ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label
1157ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                        : R.string.add_bcc_label));
1158ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            } else {
1159ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                ccBcc.setVisible(false);
1160ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            }
1161ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
116275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        if (mSave != null) {
116375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mSave.setEnabled(shouldSave());
116475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
1165ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        return true;
1166ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1167ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1168ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    @Override
1169b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    public boolean onOptionsItemSelected(MenuItem item) {
1170b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        int id = item.getItemId();
117175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        boolean handled = true;
1172b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        switch (id) {
11737b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira            case R.id.add_attachment:
1174013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira                doAttach();
11757b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira                break;
1176ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            case R.id.add_cc_bcc:
1177ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira                showCcBccViews();
1178b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira                break;
117933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.save:
1180eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                doSave(true, false);
118133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
118233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira            case R.id.send:
118333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                doSend();
118475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                break;
1185efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira            case R.id.discard:
1186efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                doDiscard();
1187efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                break;
11881f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira            case R.id.settings:
11891f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                Utils.showSettings(this, mAccount);
11901f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira                break;
1191fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case android.R.id.home:
1192fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                finish();
1193fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1194fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.help_info_menu_item:
1195fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                // TODO: enable context sensitive help
1196498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook                Utils.showHelp(this, mAccount, null);
1197fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
1198fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira            case R.id.feedback_menu_item:
1199fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                Utils.sendFeedback(this, mAccount);
1200fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira                break;
120175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            default:
120275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                handled = false;
120333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira                break;
1204b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        }
1205b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira        return !handled ? super.onOptionsItemSelected(item) : handled;
1206b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira    }
1207326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
120833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    private void doSend() {
120982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        sendOrSaveWithSanityChecks(false, true, false);
121033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
121133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
1212eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void doSave(boolean showToast, boolean resetIME) {
1213eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        sendOrSaveWithSanityChecks(true, showToast, false);
1214eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (resetIME) {
1215eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // Clear the IME composing suggestions from the body.
1216eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            BaseInputConnection.removeComposingSpans(mBodyView.getEditableText());
1217eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
121882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
121982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
122082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ interface SendOrSaveCallback {
122182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask);
12227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message);
12237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        public Message getMessage();
122482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success);
122582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
122682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
122782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ static class SendOrSaveTask implements Runnable {
122882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final Context mContext;
122982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        private final SendOrSaveCallback mSendOrSaveCallback;
123082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @VisibleForTesting
123182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final SendOrSaveMessage mSendOrSaveMessage;
123282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
123382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public SendOrSaveTask(Context context, SendOrSaveMessage message,
123482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                SendOrSaveCallback callback) {
123582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mContext = context;
123682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback = callback;
123782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveMessage = message;
123882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
123982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
124082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        @Override
124182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        public void run() {
12427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage;
124382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
124492551d057965689f1952faeb06763f0762bc717fMindy Pereira            final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount;
12457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            Message message = mSendOrSaveCallback.getMessage();
12467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID;
124782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // If a previous draft has been saved, in an account that is different
124882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // than what the user wants to send from, remove the old draft, and treat this
124982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // as a new message
12507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) {
125182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                if (messageId != UIProvider.INVALID_MESSAGE_ID) {
125282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentResolver resolver = mContext.getContentResolver();
125382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    ContentValues values = new ContentValues();
125482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    values.put(BaseColumns._ID, messageId);
125592551d057965689f1952faeb06763f0762bc717fMindy Pereira                    if (selectedAccount.account.expungeMessageUri != null) {
125692551d057965689f1952faeb06763f0762bc717fMindy Pereira                        resolver.update(selectedAccount.account.expungeMessageUri, values, null,
1257eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                                null);
1258cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    } else {
1259cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                        // TODO(mindyp) delete the conversation.
1260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira                    }
126182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    // reset messageId to 0, so a new message will be created
126282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    messageId = UIProvider.INVALID_MESSAGE_ID;
126382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                }
126482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
126582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
126682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            final long messageIdToSave = messageId;
126782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) {
12687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave);
126982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mContext.getContentResolver().update(
12707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri),
12717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sendOrSaveMessage.mValues, null, null);
127282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            } else {
12737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                ContentResolver resolver = mContext.getContentResolver();
127492551d057965689f1952faeb06763f0762bc717fMindy Pereira                Uri messageUri = resolver
127592551d057965689f1952faeb06763f0762bc717fMindy Pereira                        .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri
127692551d057965689f1952faeb06763f0762bc717fMindy Pereira                                : selectedAccount.account.sendMessageUri,
127792551d057965689f1952faeb06763f0762bc717fMindy Pereira                                sendOrSaveMessage.mValues);
12787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sendOrSaveMessage.mSave && messageUri != null) {
12797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Cursor messageCursor = resolver.query(messageUri,
12807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            UIProvider.MESSAGE_PROJECTION, null, null, null);
1281ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                    if (messageCursor != null) {
1282ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        try {
1283ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            if (messageCursor.moveToFirst()) {
1284ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // Broadcast notification that a new message has
1285ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                // been allocated
1286ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage,
1287ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                                        new Message(messageCursor));
1288ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            }
1289ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        } finally {
1290ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                            messageCursor.close();
1291ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook                        }
12927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
12937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
129482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
129582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
12967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            if (!sendOrSaveMessage.mSave) {
129782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
12987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO));
129982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
13007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC));
130182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                UIProvider.incrementRecipientsTimesContacted(mContext,
13027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC));
130382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
130482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true);
130582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
130682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
130782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
130882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // Array of the outstanding send or save tasks.  Access is synchronized
130982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    // with the object itself
131082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /* package for testing */
131182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList();
131282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private int mRequestId;
1313bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String mSignature;
131482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
131582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /*package*/ static class SendOrSaveMessage {
131692551d057965689f1952faeb06763f0762bc717fMindy Pereira        final ReplyFromAccount mAccount;
131782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final ContentValues mValues;
13183ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira        final String mRefMessageId;
131982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final boolean mSave;
132082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        final int mRequestId;
132182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
132292551d057965689f1952faeb06763f0762bc717fMindy Pereira        public SendOrSaveMessage(ReplyFromAccount account, ContentValues values,
13233ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira                String refMessageId, boolean save) {
132482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mAccount = account;
132582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mValues = values;
132682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRefMessageId = refMessageId;
132782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave = save;
132882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRequestId = mValues.hashCode() ^ hashCode();
132982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
133082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
133182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int requestId() {
133282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return mRequestId;
133382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
133482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
133582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
133682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
133782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the to recipients.
133882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
133982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getToAddresses() {
134082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mTo);
134182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
134282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
134382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
134482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the cc recipients.
134582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
134682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getCcAddresses() {
134782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mCc);
134882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
134982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
135082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
135182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Get the bcc recipients.
135282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
135382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getBccAddresses() {
135482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return getAddressesFromList(mBcc);
135582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
135682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
135782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public String[] getAddressesFromList(RecipientEditTextView list) {
135882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (list == null) {
135982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            return new String[0];
136082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
136182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText());
136282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        int count = tokens.length;
136382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        String[] result = new String[count];
136482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (int i = 0; i < count; i++) {
136582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            result[i] = tokens[i].toString();
136682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
136782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return result;
136882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
136982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
137082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
137182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Check for invalid email addresses.
137282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param to String array of email addresses to check.
137382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param wrongEmailsOut Emails addresses that were invalid.
137482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
137582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) {
137682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        for (String email : to) {
137782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (!mValidator.isValid(email)) {
137882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                wrongEmailsOut.add(email);
137982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
138082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
138182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
138282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
138382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
138482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Show an error because the user has entered an invalid recipient.
138582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param message
138682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
138782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void showRecipientErrorDialog(String message) {
138882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // Only 1 invalid recipients error dialog should be allowed up at a
138982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // time.
139082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mRecipientErrorDialog != null) {
139182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mRecipientErrorDialog.dismiss();
139282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
139382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle(
139482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                R.string.recipient_error_dialog_title)
139582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
139682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setCancelable(false)
139782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                .setPositiveButton(
139882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        R.string.ok, new Dialog.OnClickListener() {
139982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            public void onClick(DialogInterface dialog, int which) {
140082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // after the user dismisses the recipient error
140182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // dialog we want to make sure to refocus the
140282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // recipient to field so they can fix the issue
140382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                // easily
140482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                if (mTo != null) {
140582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                    mTo.requestFocus();
140682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                }
140782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                                mRecipientErrorDialog = null;
140882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                            }
140982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                        }).show();
141082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
141182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
141282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
141382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Update the state of the UI based on whether or not the current draft
141482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * needs to be saved and the message is not empty.
141582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
1416eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void updateSaveUi() {
141782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
141882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled((shouldSave() && !isBlank()));
141982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
142082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
142182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
142282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
142382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Returns true if we need to save the current draft.
142482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
142582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private boolean shouldSave() {
14267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
142782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // The message should only be saved if:
142882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // It hasn't been sent AND
142982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Some text has been added to the message OR
143082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // an attachment has been added or removed
1431eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return (mTextChanged || mAttachmentsChanged ||
143282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                    (mReplyFromChanged && !isBlank()));
143382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
143482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
143582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
143682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1437bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     * Check if all fields are blank.
143882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @return boolean
143982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
144082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public boolean isBlank() {
144182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        return mSubject.getText().length() == 0
1442bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature,
1443bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                        mBodyView.getText().toString()) == 0)
1444bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mTo.length() == 0
1445bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mCc.length() == 0 && mBcc.length() == 0
1446bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && mAttachmentsView.getAttachments().size() == 0;
1447bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1448bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1449bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    @VisibleForTesting
1450bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    protected int getSignatureStartPosition(String signature, String bodyText) {
1451bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int startPos = -1;
1452bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1453bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) {
1454bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            return startPos;
1455bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1456bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1457bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int bodyLength = bodyText.length();
1458bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int signatureLength = signature.length();
1459bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String printableVersion = convertToPrintableSignature(signature);
1460bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        int printableLength = printableVersion.length();
1461bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1462bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (bodyLength >= printableLength
1463bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - printableLength)
1464bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(printableVersion)) {
1465bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - printableLength;
1466bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        } else if (bodyLength >= signatureLength
1467bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                && bodyText.substring(bodyLength - signatureLength)
1468bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira                .equals(signature)) {
1469bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            startPos = bodyLength - signatureLength;
1470bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1471bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return startPos;
147282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
147382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
147482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
147582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Allows any changes made by the user to be ignored. Called when the user
147682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * decides to discard a draft.
147782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
147882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void discardChanges() {
147982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mTextChanged = false;
1480eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = false;
148182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        mReplyFromChanged = false;
148233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira    }
148333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira
148482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
1485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param body
1486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param save
1487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @param showToast
1488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return Whether the send or save succeeded.
1489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast,
1491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            final boolean orientationChanged) {
1492181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1493181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        Editable body = mBodyView.getEditableText();
1494181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1495181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1496181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1497181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1498181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1499181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1500181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1501181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1502181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1503181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send to nobody (but it's okay to save a message
1504181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // with no recipients)
1505181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) {
1506181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(getString(R.string.recipient_needed));
1507181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1508181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1509181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1510181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        List<String> wrongEmails = new ArrayList<String>();
1511181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1512181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(to, wrongEmails);
1513181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(cc, wrongEmails);
1514181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            checkInvalidEmails(bcc, wrongEmails);
1515181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1517181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't let the user send an email with invalid recipients
1518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (wrongEmails.size() > 0) {
1519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            String errorText = String.format(getString(R.string.invalid_recipient),
1520181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    wrongEmails.get(0));
1521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            showRecipientErrorDialog(errorText);
1522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return false;
1523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1525181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
1526181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            public void onClick(DialogInterface dialog, int which) {
1527181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged);
1528181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1529181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1530181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1531181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Show a warning before sending only if there are no attachments.
1532181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1533181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) {
1534181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptySubject = isSubjectEmpty();
1535181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean emptyBody = TextUtils.getTrimmedLength(body) == 0;
1536181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // A warning about an empty body may not be warranted when
1538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // forwarding mails, since a common use case is to forward
1539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // quoted text and not append any more text.
1540181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty());
1541181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1542181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // When we bring up a dialog warning the user about a send,
1543181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // assume that they accept sending the message. If they do not,
1544181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                // the dialog listener is required to enable sending again.
1545181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptySubject) {
1546181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener);
1547181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1548181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1549181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1550181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (warnAboutEmptyBody) {
1551181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener);
1552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    return true;
1553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Ask for confirmation to send (if always required)
1556181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (showSendConfirmation()) {
1557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                showSendConfirmDialog(R.string.confirm_send_message, listener);
1558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                return true;
1559181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
1560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        sendOrSave(body, save, showToast, false);
1563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return true;
1564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1567181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether warnings should be shown for empty
1568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * subject and body fields
1569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be shown for empty text fields
1571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showEmptyTextWarnings() {
1573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mAttachmentsView.getAttachments().size() == 0;
1574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1576181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns a boolean indicating whether the user should confirm each send
1578181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1579181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return True if a warning should be on each send
1580181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    protected boolean showSendConfirmation() {
1582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return mCachedSettings != null ? mCachedSettings.confirmSend : false;
1583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) {
1586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendConfirmDialog != null) {
1587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog.dismiss();
1588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendConfirmDialog = null;
1589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId)
1591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setTitle(R.string.confirm_send_title)
1592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setIconAttribute(android.R.attr.alertDialogIcon)
1593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setPositiveButton(R.string.send, listener)
1594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                .setNegativeButton(R.string.cancel, this).setCancelable(false).show();
1595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1597181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1598181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Returns whether the ComposeArea believes there is any text in the body of
1599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * the composition. TODO: When ComposeArea controls the Body as well, add
1600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * that here.
1601181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isBodyEmpty() {
1603181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return !mQuotedTextView.isTextIncluded();
1604181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Test to see if the subject is empty.
1608181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     *
1609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * @return boolean.
1610181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // TODO: this will likely go away when composeArea.focus() is implemented
1612181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    // after all the widget control is moved over.
1613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    public boolean isSubjectEmpty() {
1614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return TextUtils.getTrimmedLength(mSubject.getText()) == 0;
1615181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /* package */
161892551d057965689f1952faeb06763f0762bc717fMindy Pereira    static int sendOrSaveInternal(Context context, final ReplyFromAccount replyFromAccount,
161992551d057965689f1952faeb06763f0762bc717fMindy Pereira            String fromAddress, final Spanned body, final String[] to, final String[] cc,
162092551d057965689f1952faeb06763f0762bc717fMindy Pereira            final String[] bcc, final String subject, final CharSequence quotedText,
162192551d057965689f1952faeb06763f0762bc717fMindy Pereira            final List<Attachment> attachments, final Message refMessage,
162292551d057965689f1952faeb06763f0762bc717fMindy Pereira            SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) {
162329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        ContentValues values = new ContentValues();
162429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
1625c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        String refMessageId = refMessage != null ? refMessage.uri.toString() : "";
1626c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira
162729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putToAddresses(values, to);
162829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putCcAddresses(values, cc);
162929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putBccAddresses(values, bcc);
163029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira
163192551d057965689f1952faeb06763f0762bc717fMindy Pereira        MessageModification.putCustomFromAddress(values, replyFromAccount.address);
163292551d057965689f1952faeb06763f0762bc717fMindy Pereira
163329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        MessageModification.putSubject(values, subject);
163429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        String htmlBody = Html.toHtml(body);
163529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        boolean includeQuotedText = !TextUtils.isEmpty(quotedText);
163629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        StringBuilder fullBody = new StringBuilder(htmlBody);
163729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        if (includeQuotedText) {
1638e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            // HTML gets converted to text for now
1639e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            final String text = quotedText.toString();
1640e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira            if (QuotedTextView.containsQuotedText(text)) {
1641e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                int pos = QuotedTextView.getQuotedTextOffset(text);
1642e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text.substring(0, pos));
1643ffe6bb0e2af5a0d4e7a51bd060829a348b121da5Paul Westbrook                MessageModification.putQuoteStartPos(values, fullBody.length());
164412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD);
1645e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                MessageModification.putAppendRefMessageContent(values, includeQuotedText);
164629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            } else {
1647e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                LogUtils.w(LOG_TAG, "Couldn't find quoted text");
1648e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // This shouldn't happen, but just use what we have,
1649e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                // and don't do server-side expansion
1650e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira                fullBody.append(text);
165129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira            }
165229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira        }
165312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        int draftType = -1;
165412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        switch (composeMode) {
165512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.COMPOSE:
165612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.COMPOSE;
165712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
165812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.REPLY:
165912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.REPLY;
166012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
166112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.REPLY_ALL:
166212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.REPLY_ALL;
166312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
166412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            case ComposeActivity.FORWARD:
166512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                draftType = DraftType.FORWARD;
166612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                break;
166712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
166812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        MessageModification.putDraftType(values, draftType);
1669c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        if (refMessage != null) {
1670c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyHtml)) {
1671c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBodyHtml(values, fullBody.toString());
1672c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
1673c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            if (!TextUtils.isEmpty(refMessage.bodyText)) {
1674c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira                MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
1675c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira            }
1676c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira        } else {
1677c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBodyHtml(values, fullBody.toString());
1678c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira            MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString());
1679c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira        }
1680f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        MessageModification.putAttachments(values, attachments);
168112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        if (!TextUtils.isEmpty(refMessageId)) {
168212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira            MessageModification.putRefMessageId(values, refMessageId);
168312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira        }
168482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
168592551d057965689f1952faeb06763f0762bc717fMindy Pereira        SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount,
1686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                values, refMessageId, save);
1687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback);
168882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        callback.initializeSendOrSave(sendOrSaveTask);
169082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Do the send/save action on the specified handler to avoid possible
1692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // ANRs
1693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        handler.post(sendOrSaveTask);
169482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        return sendOrSaveMessage.requestId();
1696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
169782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void sendOrSave(Spanned body, boolean save, boolean showToast,
1699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            boolean orientationChanged) {
1700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Check if user is a monkey. Monkeys can compose and hit send
1701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // button but are not allowed to send anything off the device.
17023ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook        if (ActivityManager.isUserAMonkey()) {
1703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            return;
1704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
170582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String[] to, cc, bcc;
1707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (orientationChanged) {
1708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = cc = bcc = new String[0];
1709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        } else {
1710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            to = getToAddresses();
1711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            cc = getCcAddresses();
1712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            bcc = getBccAddresses();
1713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
171482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1715181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        SendOrSaveCallback callback = new SendOrSaveCallback() {
171682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            private int mRestoredRequestId;
171782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
171882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) {
1719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mActiveTasks) {
1720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    int numTasks = mActiveTasks.size();
1721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    if (numTasks == 0) {
1722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // Start service so we won't be killed if this app is
1723181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        // put in the background.
1724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                        startService(new Intent(ComposeActivity.this, EmptyService.class));
1725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    }
1726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mActiveTasks.add(sendOrSaveTask);
1728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
1730181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask);
1731181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1732181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
173382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
17347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage,
17357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Message message) {
1736181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                synchronized (mDraftLock) {
1737181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraftId = message.id;
1738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    mDraft = message;
17397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    if (sRequestMessageIdMap != null) {
17407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                        sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId);
17417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    }
1742181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    // Cache request message map, in case the process is killed
1743181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    saveRequestMap();
1744181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1745181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                if (sTestSendOrSaveCallback != null) {
17467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message);
1747181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                }
1748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
174982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
17507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public Message getMessage() {
17517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mDraftLock) {
17527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    return mDraft;
17537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
17547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
175582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
17567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            public void sendOrSaveFinished(SendOrSaveTask task, boolean success) {
17577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (success) {
17587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Successfully sent or saved so reset change markers
17597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    discardChanges();
17607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                } else {
17617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // A failure happened with saving/sending the draft
17627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // TODO(pwestbro): add a better string that should be used
17637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // when failing to send or save
17647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT)
17657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                            .show();
17667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
176782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
17687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                int numTasks;
17697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                synchronized (mActiveTasks) {
17707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Remove the task from the list of active tasks
17717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    mActiveTasks.remove(task);
17727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    numTasks = mActiveTasks.size();
17737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
177482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
17757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (numTasks == 0) {
17767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    // Stop service so we can be killed.
17777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    stopService(new Intent(ComposeActivity.this, EmptyService.class));
17787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
17797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                if (sTestSendOrSaveCallback != null) {
17807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                    sTestSendOrSaveCallback.sendOrSaveFinished(task, success);
17817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira                }
17827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira            }
1783181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        };
1784181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1785181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Get the selected account if the from spinner has been setup.
178692551d057965689f1952faeb06763f0762bc717fMindy Pereira        ReplyFromAccount selectedAccount = mReplyFromAccount;
1787181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        String fromAddress = selectedAccount.name;
1788181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (selectedAccount == null || fromAddress == null) {
1789181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // We don't have either the selected account or from address,
1790181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // use mAccount.
179192551d057965689f1952faeb06763f0762bc717fMindy Pereira            selectedAccount = mReplyFromAccount;
1792181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            fromAddress = mAccount.name;
1793181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1794181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1795181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mSendSaveTaskHandler == null) {
1796181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            HandlerThread handlerThread = new HandlerThread("Send Message Task Thread");
1797181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            handlerThread.start();
1798181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1799181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mSendSaveTaskHandler = new Handler(handlerThread.getLooper());
1800181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1801181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
180292551d057965689f1952faeb06763f0762bc717fMindy Pereira        mRequestId = sendOrSaveInternal(this, mReplyFromAccount, fromAddress, body, to, cc,
1803ffe6bb0e2af5a0d4e7a51bd060829a348b121da5Paul Westbrook                bcc, mSubject.getText().toString(), mQuotedTextView.getQuotedTextIfIncluded(),
1804c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira                mAttachmentsView.getAttachments(), mRefMessage, callback,
180512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira                mSendSaveTaskHandler, save, mComposeMode);
1806181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1807181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (mRecipient != null && mRecipient.equals(mAccount.name)) {
1808181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mRecipient = selectedAccount.name;
1809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1810b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook        setAccount(selectedAccount.account);
1811181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1812181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Don't display the toast if the user is just changing the orientation,
1813181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // but we still need to save the draft to the cursor because this is how we restore
1814181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // the attachments when the configuration change completes.
1815181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
1816181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message,
1817181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                    Toast.LENGTH_LONG).show();
1818181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1819181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1820181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // Need to update variables here because the send or save completes
1821181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // asynchronously even though the toast shows right away.
1822181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        discardChanges();
1823181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        updateSaveUi();
1824181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1825181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // If we are sending, finish the activity
1826181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (!save) {
1827181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            finish();
1828181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        }
1829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
1830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira
1831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    /**
1832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * Save the state of the request messageid map. This allows for the Gmail
1833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * process to be killed, but and still allow for ComposeActivity instances
1834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     * to be recreated correctly.
1835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira     */
1836181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    private void saveRequestMap() {
1837181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        // TODO: store the request map in user preferences.
1838181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira    }
183982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
1840013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    public void doAttach() {
1841013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
1842013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        i.addCategory(Intent.CATEGORY_OPENABLE);
1843181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        if (android.provider.Settings.System.getInt(getContentResolver(),
1844181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                UIProvider.getAttachmentTypeSetting(), 0) != 0) {
1845013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            i.setType("*/*");
1846013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        } else {
1847013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira            i.setType("image/*");
1848013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        }
1849013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira        mAddingAttachment = true;
1850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira        startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)),
1851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                RESULT_PICK_ATTACHMENT);
1852013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira    }
1853013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira
1854ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    private void showCcBccViews() {
1855a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        mCcBccView.show(true, true, true);
1856ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        if (mCcBccButton != null) {
1857ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira            mCcBccButton.setVisibility(View.GONE);
1858ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira        }
1859ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira    }
1860ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira
1861326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
1862326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onNavigationItemSelected(int position, long itemId) {
1863a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        int initialComposeMode = mComposeMode;
1864326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (position == ComposeActivity.REPLY) {
1865326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY;
1866326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.REPLY_ALL) {
1867326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.REPLY_ALL;
1868326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (position == ComposeActivity.FORWARD) {
1869326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComposeMode = ComposeActivity.FORWARD;
1870326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1871a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        if (initialComposeMode != mComposeMode) {
1872154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            resetMessageForModeChange();
18738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            if (mRefMessage != null) {
18748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira                initFromRefMessage(mComposeMode, mAccount.name);
18758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira            }
1876a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira        }
1877326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return true;
1878326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1879326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1880154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    private void resetMessageForModeChange() {
1881154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // When switching between reply, reply all, forward,
1882154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // follow the behavior of webview.
1883154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // The contents of the following fields are cleared
1884154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // so that they can be populated directly from the
1885154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // ref message:
1886154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Any recipient fields
1887154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) The subject
1888154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mTo.setText("");
1889154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mCc.setText("");
1890154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mBcc.setText("");
1891154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any edits to the subject are replaced with the original subject.
1892154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        mSubject.setText("");
1893154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
1894154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // Any changes to the contents of the following fields are kept:
1895154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 1) Body
1896154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // 2) Attachments
1897154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        // If the user made changes to attachments, keep their changes.
1898154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        if (!mAttachmentsChanged) {
1899154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira            mAttachmentsView.deleteAllAttachments();
1900154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira        }
1901154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira    }
1902154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira
1903326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private class ComposeModeAdapter extends ArrayAdapter<String> {
1904326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1905326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater mInflater;
1906326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1907326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public ComposeModeAdapter(Context context) {
1908326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            super(context, R.layout.compose_mode_item, R.id.mode, getResources()
1909326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    .getStringArray(R.array.compose_modes));
1910326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1911326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1912326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private LayoutInflater getInflater() {
1913326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mInflater == null) {
1914326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mInflater = LayoutInflater.from(getContext());
1915326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1916326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mInflater;
1917326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1918326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1919326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        @Override
1920326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public View getView(int position, View convertView, ViewGroup parent) {
1921326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (convertView == null) {
1922326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                convertView = getInflater().inflate(R.layout.compose_mode_display_item, null);
1923326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1924326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position));
1925326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return super.getView(position, convertView, parent);
1926326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1927326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
192846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
192946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    @Override
193046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void onRespondInline(String text) {
193146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        appendToBody(text, false);
193246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
193346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
193446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
193546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Append text to the body of the message. If there is no existing body
193646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * text, just sets the body to text.
193746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     *
193846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
193946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
194046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
194146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void appendToBody(CharSequence text, boolean withSignature) {
1942eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        Editable bodyText = mBodyView.getEditableText();
194346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        if (bodyText != null && bodyText.length() > 0) {
194446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            bodyText.append(text);
194546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        } else {
194646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira            setBody(text, withSignature);
194746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira        }
194846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
194946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira
195046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    /**
195146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * Set the body of the message.
1952bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira     *
195346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param text
195446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     * @param withSignature True to append a signature.
195546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira     */
195646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    public void setBody(CharSequence text, boolean withSignature) {
1957eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mBodyView.setText(text);
1958bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (withSignature) {
1959bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            appendSignature();
1960bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1961bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1962bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1963bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private void appendSignature() {
1964b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        String newSignature = mCachedSettings != null ? mCachedSettings.signature : null;
1965433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira        boolean hasFocus = mBodyView.hasFocus();
1966b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira        if (!TextUtils.equals(newSignature, mSignature)) {
1967b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            mSignature = newSignature;
1968b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            if (!TextUtils.isEmpty(mSignature)
1969b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                    && getSignatureStartPosition(mSignature,
1970b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                            mBodyView.getText().toString()) < 0) {
1971b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                // Appending a signature does not count as changing text.
1972b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.removeTextChangedListener(this);
1973b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.append(convertToPrintableSignature(mSignature));
1974b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira                mBodyView.addTextChangedListener(this);
1975b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira            }
1976433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            if (hasFocus) {
1977433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira                focusBody();
1978433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira            }
1979bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1980bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    }
1981bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira
1982bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira    private String convertToPrintableSignature(String signature) {
1983bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        String signatureResource = getResources().getString(R.string.signature);
1984bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        if (signature == null) {
1985bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira            signature = "";
1986bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        }
1987bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira        return String.format(signatureResource, signature);
198846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira    }
19891a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira
19905a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    @Override
19915a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira    public void onAccountChanged() {
199292551d057965689f1952faeb06763f0762bc717fMindy Pereira        mReplyFromAccount = mFromSpinner.getCurrentAccount();
199392551d057965689f1952faeb06763f0762bc717fMindy Pereira        if (!mAccount.equals(mReplyFromAccount.account)) {
1994b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook            setAccount(mReplyFromAccount.account);
1995b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook
1996181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // TODO: handle discarding attachments when switching accounts.
1997181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // Only enable save for this draft if there is any other content
1998181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            // in the message.
1999181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            if (!isBlank()) {
2000181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira                enableSave(true);
2001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            }
2002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            mReplyFromChanged = true;
2003181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira            initRecipients();
200482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
20051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira    }
200682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
200782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSave(boolean enabled) {
200882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSave != null) {
200982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSave.setEnabled(enabled);
201082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
201182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
201282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
201382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void enableSend(boolean enabled) {
201482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (mSend != null) {
201582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            mSend.setEnabled(enabled);
201682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
201782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
201882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
201982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
202082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Handles button clicks from any error dialogs dealing with sending
202182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * a message.
202282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
202382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    @Override
202482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    public void onClick(DialogInterface dialog, int which) {
202582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        switch (which) {
202682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_POSITIVE: {
202782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                doDiscardWithoutConfirmation(true /* show toast */ );
202882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
202982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
203082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            case DialogInterface.BUTTON_NEGATIVE: {
203182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // If the user cancels the send, re-enable the send button.
203282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                enableSend(true);
203382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                break;
203482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
203582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
203682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
203782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
203882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2039efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    private void doDiscard() {
2040efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira        new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text)
2041efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setPositiveButton(R.string.ok, this)
2042efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .setNegativeButton(R.string.cancel, null)
2043efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira                .create().show();
2044efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira    }
204582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    /**
204682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * Effectively discard the current message.
204782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     *
204882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * This method is either invoked from the menu or from the dialog
204982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * once the user has confirmed that they want to discard the message.
205082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     * @param showToast show "Message discarded" toast if true
205182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira     */
205282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    private void doDiscardWithoutConfirmation(boolean showToast) {
20537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira        synchronized (mDraftLock) {
205482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            if (mDraftId != UIProvider.INVALID_MESSAGE_ID) {
205582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                ContentValues values = new ContentValues();
2056b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook                values.put(BaseColumns._ID, mDraftId);
2057cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                if (mAccount.expungeMessageUri != null) {
2058cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    getContentResolver().update(mAccount.expungeMessageUri, values, null, null);
2059cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                } else {
2060cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                    // TODO(mindyp): call delete on this conversation instead.
2061cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira                }
206282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // This is not strictly necessary (since we should not try to
206382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // save the draft after calling this) but it ensures that if we
206482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // do save again for some reason we make a new draft rather than
206582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                // trying to resave an expunged draft.
206682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira                mDraftId = UIProvider.INVALID_MESSAGE_ID;
206782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            }
206882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
206982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
207082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        if (showToast) {
207182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            // Display a toast to let the user know
207282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira            Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show();
207382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        }
207482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
207582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        // This prevents the draft from being saved in onPause().
207682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        discardChanges();
207782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira        finish();
207882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira    }
207982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira
2080eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeeded() {
2081eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2082eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2083eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2084eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2085eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2086eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2087eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2088eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
2089eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            doSave(!mAddingAttachment /* show toast */, true /* reset IME */);
2090eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2091eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2092eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2093eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    private void saveIfNeededOnOrientationChanged() {
2094eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (mAccount == null) {
2095eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // We have not chosen an account yet so there's no way that we can save. This is ok,
2096eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // though, since we are saving our state before AccountsActivity is activated. Thus, the
2097eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // user has not interacted with us yet and there is no real state to save.
2098eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            return;
2099eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2100eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2101eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (shouldSave()) {
2102eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            doSaveOrientationChanged(!mAddingAttachment /* show toast */, true /* reset IME */);
2103eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2104eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2105eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2106eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    /**
2107eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira     * Save a draft if a draft already exists or the message is not empty.
2108eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira     */
2109eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void doSaveOrientationChanged(boolean showToast, boolean resetIME) {
2110eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        saveOnOrientationChanged();
2111eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        if (resetIME) {
2112eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            // Clear the IME composing suggestions from the body.
2113eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira            BaseInputConnection.removeComposingSpans(mBodyView.getEditableText());
2114eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        }
2115eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2116eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2117eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    protected boolean saveOnOrientationChanged() {
2118eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        return sendOrSaveWithSanityChecks(true, false, true);
2119eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
2120eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira
2121eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    @Override
2122eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    public void onAttachmentDeleted() {
2123eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        mAttachmentsChanged = true;
2124eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira        updateSaveUi();
2125eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira    }
212675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
212775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
212875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    /**
212975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     * This is called any time one of our text fields changes.
213075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira     */
213175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void afterTextChanged(Editable s) {
213275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        mTextChanged = true;
213375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        updateSaveUi();
213475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
213575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
213675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    @Override
213775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
213875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
213975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
214075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
214175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    public void onTextChanged(CharSequence s, int start, int before, int count) {
214275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        // Do nothing.
214375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
214475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
214575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
214675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // There is a big difference between the text associated with an address changing
214775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // to add the display name or to format properly and a recipient being added or deleted.
214875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    // Make sure we only notify of changes when a recipient has been added or deleted.
214975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    private class RecipientTextWatcher implements TextWatcher {
215075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private HashMap<String, Integer> mContent = new HashMap<String, Integer>();
215175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
215275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private RecipientEditTextView mView;
215375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
215475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private TextWatcher mListener;
215575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
215675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) {
215775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mView = view;
215875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            mListener = listener;
215975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
216075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
216175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
216275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void afterTextChanged(Editable s) {
216375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (hasChanged()) {
216475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                mListener.afterTextChanged(s);
216575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
216675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
216775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
216875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private boolean hasChanged() {
216975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] currRecips = tokenizeRecips(getAddressesFromList(mView));
217075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalCount = currRecips.length;
217175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            int totalPrevCount = 0;
217275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (Entry<String, Integer> entry : mContent.entrySet()) {
217375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                totalPrevCount += entry.getValue();
217475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
217575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            if (totalCount != totalPrevCount) {
217675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                return true;
217775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
217875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
217975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : currRecips) {
218075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
218175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    return true;
218275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
218375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    int count = mContent.get(recip) - 1;
218475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    if (count < 0) {
218575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        return true;
218675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    } else {
218775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                        mContent.put(recip, count);
218875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    }
218975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
219075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
219175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return false;
219275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
219375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
219475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        private String[] tokenizeRecips(String[] recips) {
219575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Tokenize them all and put them in the list.
219675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recipAddresses = new String[recips.length];
219775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (int i = 0; i < recips.length; i++) {
219875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress();
219975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
220075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            return recipAddresses;
220175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
220275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
220375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
220475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
220575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            String[] recips = tokenizeRecips(getAddressesFromList(mView));
220675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            for (String recip : recips) {
220775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                if (!mContent.containsKey(recip)) {
220875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, 1);
220975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                } else {
221075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                    mContent.put(recip, (mContent.get(recip)) + 1);
221175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira                }
221275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            }
221375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
221475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira
221575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        @Override
221675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        public void onTextChanged(CharSequence s, int start, int before, int count) {
221775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira            // Do nothing.
221875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira        }
221975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira    }
22208e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira}