ComposeActivity.java revision 26d4d2d9c43c499f458808f050ec73ea3c28dec4
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 19ebc4bda7184ce659144eb95c7e73cb77ce3384daAndrew Sappersteinimport android.animation.LayoutTransition; 20326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar; 215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener; 225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity; 2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager; 2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog; 2582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog; 26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment; 27b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentManager; 28b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction; 2996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager; 306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver; 3182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues; 326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context; 3396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader; 3482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface; 356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent; 3696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader; 3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo; 387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor; 396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri; 408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle; 4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler; 4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread; 43f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable; 4482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns; 4546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable; 4682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html; 4782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned; 48c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils; 4982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher; 5046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token; 51c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity; 5362d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent; 54326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater; 55b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu; 56b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater; 57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem; 588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View; 598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener; 605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup; 61eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection; 6262d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo; 63326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 648e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 65433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText; 666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 67013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 687b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 69c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView; 715c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R; 7240882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener; 739932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 745a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 7530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 7633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 7730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 795ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereiraimport com.android.mail.providers.Folder; 8047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider; 813ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 8282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 8392551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount; 84181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 8530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 863ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 8712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 88fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity; 89b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment; 9062066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.android.mail.ui.AttachmentTile.AttachmentPreview; 9192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 92434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils; 93b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 9430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 9530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 9646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 9782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 998e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 10062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException; 10162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 1028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 1038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 10446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 105bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 10646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 10775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 10846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 10946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 1101c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 111bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 11282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 11446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 1155a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira RespondInlineListener, DialogInterface.OnClickListener, TextWatcher, 11640882430c874ff29890ec6fa31f7649788cbc470mindyp AttachmentAddedOrDeletedListener, OnAccountChangedListener, LoaderManager.LoaderCallbacks<Cursor>, 11762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp TextView.OnEditorActionListener { 1186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 11936bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int COMPOSE = -1; 12036bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int REPLY = 0; 12136bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int REPLY_ALL = 1; 12236bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int FORWARD = 2; 12336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int EDIT_DRAFT = 3; 1246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 12696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira protected static final String EXTRA_ACTION = "action"; 1276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 128326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_CC = "showCc"; 129326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_BCC = "showBcc"; 130a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira 1318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1399a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira private static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString"; 1409a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 14162066e47fe69c33b60ed970e46809ba81d044064Mark Wei private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews"; 14262066e47fe69c33b60ed970e46809ba81d044064Mark Wei 1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_TO = "to"; 1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 1498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC }; 1508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 15182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 15282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 15382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 15482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 15582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 15682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 15782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 15882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 16482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Key used to store the above map 16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids"; 1666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 172daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook public static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 174e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String EXTRA_ATTACHMENTS = "attachments"; 175f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1763ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 17736bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 178b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira // If this is a reply/forward then this extra will hold a uri we must query 179b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira // to get the original message. 180b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri"; 181434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei // If this is an action to edit an existing draft message, this extra will hold the 182bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 183bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 1844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 185b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 186013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 187013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 188013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 1898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 190e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 1918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 192e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount"; 193e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_REQUEST_ID = "requestId"; 194e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart"; 195e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_END = null; 196e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_MESSAGE = "extraMessage"; 19796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira private static final int REFERENCE_MESSAGE_LOADER = 0; 198b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private static final int LOADER_ACCOUNT_CURSOR = 1; 19947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount"; 200b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private static final String TAG_WAIT = "wait-fragment"; 2012db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private static final String MIME_TYPE_PHOTO = "image/*"; 2022db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private static final String MIME_TYPE_VIDEO = "video/*"; 2038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 20482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 20582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 20682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 20782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 208c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 209c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 210c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 2118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 2128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 2137b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 21433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private Account mAccount; 21592551d057965689f1952faeb06763f0762bc717fMindy Pereira private ReplyFromAccount mReplyFromAccount; 216181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 21782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 2186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 2196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 220326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 221326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private int mComposeMode = -1; 22246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 22346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private String mRecipient; 22446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 225433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private EditText mBodyView; 2261a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 2272eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 228eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 2291883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira @VisibleForTesting 2301883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira protected FromAddressSpinner mFromSpinner; 231013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 232eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 23382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 23482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 23582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 23682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 23782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private AlertDialog mRecipientErrorDialog; 238eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private AlertDialog mSendConfirmDialog; 239b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira @VisibleForTesting 240b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira protected Message mRefMessage; 2417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 2437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 24493b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp private View mPhotoAttachmentsButton; 24593b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp private View mVideoAttachmentsButton; 2463ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 247326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 248daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view. 249daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook */ 250daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private boolean mLaunchedFromEmail = false; 251cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mToListener; 252cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mCcListener; 253cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mBccListener; 254b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira private Uri mRefMessageUri; 255b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private Bundle mSavedInstanceState; 256daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 257daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 258daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook /** 259326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 260326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 2613ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 262bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook launch(launcher, account, message, EDIT_DRAFT); 263326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 264326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2656349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 26833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 2696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launch(launcher, account, null, COMPOSE); 2706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2753ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 2763ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY); 2776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 2833ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY_ALL); 2846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2876349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2893ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 2903ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, FORWARD); 2916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2933ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static void launch(Context launcher, Account account, Message message, int action) { 2946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 2956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 2966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 2976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 299bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 300bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 302bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 3036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 3046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3058e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 3068e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 3078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onCreate(Bundle savedInstanceState) { 3088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 3098e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 310b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mSavedInstanceState = savedInstanceState; 311b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira checkValidAccounts(); 312b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 313b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 314b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void finishCreate() { 315b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Bundle savedInstanceState = mSavedInstanceState; 31646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 317818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 318e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message; 31962066e47fe69c33b60ed970e46809ba81d044064Mark Wei ArrayList<AttachmentPreview> previews; 32071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira boolean showQuotedText = false; 321e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int action; 32247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // Check for any of the possibly supplied accounts.; 32347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Account account = null; 324f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira if (hadSavedInstanceStateMessage(savedInstanceState)) { 325e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE); 326e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT); 327e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE); 32862066e47fe69c33b60ed970e46809ba81d044064Mark Wei 32962066e47fe69c33b60ed970e46809ba81d044064Mark Wei previews = savedInstanceState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS); 330e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE); 331e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 33247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = obtainAccount(intent); 333e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 334e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // Initialize the message from the message in the intent 335e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 33662066e47fe69c33b60ed970e46809ba81d044064Mark Wei previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS); 337e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 338b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI); 339e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 34062066e47fe69c33b60ed970e46809ba81d044064Mark Wei mAttachmentsView.setAttachmentPreviews(previews); 34192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 34292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 343818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 344818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 345818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 346bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 347daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) { 348daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = true; 349daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } else if (Intent.ACTION_SEND.equals(intent.getAction())) { 350daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final Uri dataUri = intent.getData(); 351daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (dataUri != null) { 352daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String dataScheme = intent.getData().getScheme(); 353daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String accountScheme = mAccount.composeIntentUri.getScheme(); 354daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme); 355daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 356daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 357daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 35896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira if (mRefMessageUri != null) { 35996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // We have a referenced message that we must look up. 36096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this); 36196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return; 36296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } else if (message != null && action != EDIT_DRAFT) { 363e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 364e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 365a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira showCcBcc(savedInstanceState); 36671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = message.appendRefMessageContent; 367e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (action == EDIT_DRAFT) { 368e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 369ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showBcc = !TextUtils.isEmpty(message.bcc); 370ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showCc = showBcc || !TextUtils.isEmpty(message.cc); 371ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 372bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 373bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 374bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 375bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 376bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 377bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 378bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 379bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 380bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 381bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 382bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 383bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 384bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 385bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 386bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 387bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 388e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 38971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = message.appendRefMessageContent; 390e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 391e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 392e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromRefMessage(action, mAccount.name); 39371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = true; 394e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 3958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 3968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromExtras(intent); 397bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 39896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira finishSetup(action, intent, savedInstanceState, showQuotedText); 39996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 400bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 401b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void checkValidAccounts() { 402b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAccounts = AccountUtils.getAccounts(this); 403b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 404b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this); 405b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (noAccountIntent != null) { 406b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT); 407b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 408b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 40926d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp // If none of the accounts are syncing, setup a watcher. 410b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira boolean anySyncing = false; 411b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 412b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (a.isAccountIntialized()) { 413b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira anySyncing = true; 414b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 415b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 416b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 417b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (!anySyncing) { 418b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // There are accounts, but none are sync'd, which is just like having no accounts. 419b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAccounts = null; 420b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); 421b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return; 422b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 423b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishCreate(); 424b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 425b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 426b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 42747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira private Account obtainAccount(Intent intent) { 42847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Account account = null; 42947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Object accountExtra = null; 43047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (intent != null && intent.getExtras() != null) { 43147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT); 43247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (accountExtra instanceof Account) { 43347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira return (Account) accountExtra; 4347ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp } else if (accountExtra instanceof String) { 4357ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp // This is the Account attached to the widget compose intent. 4367ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp account = Account.newinstance((String)accountExtra); 4377ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp if (account != null) { 4387ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp return account; 4397ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp } 44047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 44147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = intent.getStringExtra(EXTRA_SELECTED_ACCOUNT); 44247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 44347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (account == null) { 44447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira final String lastAccountUri = MailAppProvider.getInstance().getLastSentFromAccount(); 44547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (!TextUtils.isEmpty(lastAccountUri)) { 44647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = Uri.parse(lastAccountUri); 44747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 44847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 449b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts != null && mAccounts.length > 0) { 45047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) { 45147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // For backwards compatibility, we need to check account 45247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // names. 453b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 45447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (a.name.equals(accountExtra)) { 45547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = a; 45647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 45747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 45847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } else if (accountExtra instanceof Uri) { 45947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // The uri of the last viewed account is what is stored in 46047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // the current code base. 461b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 46247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (a.uri.equals(accountExtra)) { 46347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = a; 46447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 46547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 466b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 467b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (account == null) { 468b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = mAccounts[0]; 46947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 47047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 47147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira return account; 47247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 47347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira 47496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira private void finishSetup(int action, Intent intent, Bundle savedInstanceState, 47596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira boolean showQuotedText) { 476bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == COMPOSE) { 477eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mQuotedTextView.setVisibility(View.GONE); 47846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 479818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira initRecipients(); 480f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // Don't bother with the intent if we have procured a message from the 481f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // intent already. 482f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira if (!hadSavedInstanceStateMessage(savedInstanceState)) { 483f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira initAttachmentsFromIntent(intent); 484f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 4851a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira initActionBar(action); 486e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(), 487e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action); 48875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 489433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira setFocus(action); 490326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira updateHideOrShowCcBcc(); 49171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira updateHideOrShowQuotedText(showQuotedText); 49271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira } 49371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira 494f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira private boolean hadSavedInstanceStateMessage(Bundle savedInstanceState) { 495f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE); 496f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 497f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira 49871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira private void updateHideOrShowQuotedText(boolean showQuotedText) { 49971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira mQuotedTextView.updateCheckedState(showQuotedText); 50040882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 501433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 502433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 503433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private void setFocus(int action) { 504433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (action == EDIT_DRAFT) { 505433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int type = mDraft.draftType; 506433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (type) { 507433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.COMPOSE: 508433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.FORWARD: 509433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = COMPOSE; 510433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 511433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY: 512433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY_ALL: 513433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 514433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = REPLY; 515433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 516433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 517433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 518433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (action) { 519433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case FORWARD: 520433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case COMPOSE: 521433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mTo.requestFocus(); 522433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 523433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY: 524433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY_ALL: 525433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 526433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 527433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 528433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 529433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 530433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 531433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira /** 532433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira * Focus the body of the message. 533433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira */ 534433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira public void focusBody() { 535433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.requestFocus(); 536433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int length = mBodyView.getText().length(); 537433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 538433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int signatureStartPos = getSignatureStartPosition( 539433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mSignature, mBodyView.getText().toString()); 540433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (signatureStartPos > -1) { 541433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // In case the user deleted the newlines... 542433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(signatureStartPos); 5438743cfca851058d50385951b111dd903b1fa6c5amindyp } else if (length >= 0) { 544433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // Move cursor to the end. 545433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(length); 546433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 5471a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 5481a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 5491a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 5501a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 5511a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 5521a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 5531a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 554818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 555b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount, mAccounts); 556818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 5571a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 5581a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 559eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 560eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 561eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 562eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 563eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mSendConfirmDialog != null) { 564eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mSendConfirmDialog.dismiss(); 565eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 566eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mRecipientErrorDialog != null) { 567eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mRecipientErrorDialog.dismiss(); 568eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 569a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira // When the user exits the compose view, see if this draft needs saving. 570a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira if (isFinishing()) { 571a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira saveIfNeeded(); 572a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira } 573eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 574eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 575eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 576eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 577b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) { 578eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 579b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAddingAttachment = false; 580b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else if (request == RESULT_CREATE_ACCOUNT) { 581b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // We were waiting for the user to create an account 582b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (result != RESULT_OK) { 583b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 584b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 585b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Watch for accounts to show up! 586b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // restart the loader to get the updated list of accounts 587b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); 588b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira showWaitFragment(null); 589b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 590eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 591eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 592eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 593eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 594e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira public final void onRestoreInstanceState(Bundle savedInstanceState) { 595e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira super.onRestoreInstanceState(savedInstanceState); 596e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState != null) { 597e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) { 598e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START); 599e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END); 600e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // There should be a focus and it should be an EditText since we 601e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // only save these extras if these conditions are true. 602e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) getCurrentFocus(); 603e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira final int length = focusEditText.getText().length(); 604e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectionStart < length && selectionEnd < length) { 605e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira focusEditText.setSelection(selectionStart, selectionEnd); 606e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 607e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 608e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 609e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 610e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 611e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira @Override 612eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public final void onSaveInstanceState(Bundle state) { 613eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 614b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // We have no accounts so there is nothing to compose, and therefore, nothing to save. 615b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 616b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return; 617b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 618e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // The framework is happy to save and restore the selection but only if it also saves and 619e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // restores the contents of the edit text. That's a lot of text to put in a bundle so we do 620e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // this manually. 621e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira View focus = getCurrentFocus(); 622e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (focus != null && focus instanceof EditText) { 623e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) focus; 624e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart()); 625e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd()); 626e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 6276273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook 6286273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 629151f1ad1613ecac0207144472872440517172b5aPaul Westbrook final int selectedPos = mFromSpinner.getSelectedItemPosition(); 630d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null 631d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ? 632d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira replyFromAccounts.get(selectedPos) : null; 633e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectedReplyFromAccount != null) { 634e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize() 635e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .toString()); 636e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account); 637e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 638e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount); 639e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 640eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 641e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) { 642e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We don't have a draft id, and we have a request id, 643e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // save the request id. 644e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_REQUEST_ID, mRequestId); 645e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 646e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 647e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We want to restore the current mode after a pause 648e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // or rotation. 649e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = getMode(); 650e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_ACTION, mode); 651e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 652e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = createMessage(selectedReplyFromAccount, mode); 653e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_MESSAGE, message); 654e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 655e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 656e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage); 657e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 658326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible()); 659326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible()); 66062066e47fe69c33b60ed970e46809ba81d044064Mark Wei 66162066e47fe69c33b60ed970e46809ba81d044064Mark Wei state.putParcelableArrayList( 66262066e47fe69c33b60ed970e46809ba81d044064Mark Wei EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews()); 663e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 664e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 665e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private int getMode() { 666e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = ComposeActivity.COMPOSE; 667e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ActionBar actionBar = getActionBar(); 668e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar != null 669e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) { 670e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mode = actionBar.getSelectedNavigationIndex(); 671e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 672e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return mode; 673e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 674e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 675e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) { 676e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = new Message(); 677e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.id = UIProvider.INVALID_MESSAGE_ID; 678d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang message.serverId = null; 679e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.uri = null; 680e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.conversationUri = null; 681e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.subject = mSubject.getText().toString(); 682e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.snippet = null; 6831eedc7520600a315afba4fc114a9fc5bf1adacd7Mindy Pereira message.from = selectedReplyFromAccount != null ? selectedReplyFromAccount.address 684b67aa8f5975082434dc6b8ebeedf2f1333dbf86dMindy Pereira : mAccount != null ? mAccount.name : null; 6853c9115813343861a44133b805fb9f55512d20948Mindy Pereira message.to = formatSenders(mTo.getText().toString()); 6863c9115813343861a44133b805fb9f55512d20948Mindy Pereira message.cc = formatSenders(mCc.getText().toString()); 6873c9115813343861a44133b805fb9f55512d20948Mindy Pereira message.bcc = formatSenders(mBcc.getText().toString()); 688e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.replyTo = null; 689e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.dateReceivedMs = 0; 690e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira String htmlBody = Html.toHtml(mBodyView.getText()); 691e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 692e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyHtml = fullBody.toString(); 693e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyText = mBodyView.getText().toString(); 694e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.embedsExternalResources = false; 695e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null; 696d2bef8b371784d95f60dd3f89aa0ac3557c945efMindy Pereira message.draftType = getDraftType(mode); 697e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null; 698e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ArrayList<Attachment> attachments = mAttachmentsView.getAttachments(); 699e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.hasAttachments = attachments != null && attachments.size() > 0; 700e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentListUri = null; 701e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.messageFlags = 0; 702e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.saveUri = null; 703e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.sendUri = null; 704e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.alwaysShowImages = false; 705e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentsJson = Attachment.toJSONArray(attachments); 706e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira CharSequence quotedText = mQuotedTextView.getQuotedText(); 707e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView 708e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .getQuotedTextOffset(quotedText.toString()) : -1; 709e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.accountUri = null; 710e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return message; 711eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 712eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 7133c9115813343861a44133b805fb9f55512d20948Mindy Pereira private String formatSenders(String string) { 7143c9115813343861a44133b805fb9f55512d20948Mindy Pereira if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') { 7153c9115813343861a44133b805fb9f55512d20948Mindy Pereira return string.substring(0, string.length() - 1); 7163c9115813343861a44133b805fb9f55512d20948Mindy Pereira } 7173c9115813343861a44133b805fb9f55512d20948Mindy Pereira return string; 7183c9115813343861a44133b805fb9f55512d20948Mindy Pereira } 7193c9115813343861a44133b805fb9f55512d20948Mindy Pereira 720818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 721818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 722bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira if (account == null) { 723bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira return; 724bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira } 72523e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 72623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 727b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook mCachedSettings = mAccount.settings; 728b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook appendSignature(); 72923e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 730fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira if (mAccount != null) { 731fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira MailActivity.setForegroundNdef(MailActivity.getMailtoNdef(mAccount.name)); 732fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira } 733818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 734818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 735e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromSpinner(Bundle bundle, int action) { 7369a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira String accountString = null; 737e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) { 73862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira action = COMPOSE; 73962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 740b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mFromSpinner.asyncInitFromSpinner(action, mAccount, mAccounts); 7419a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle != null) { 7429a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) { 7439a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = ReplyFromAccount.deserialize(mAccount, 7449a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)); 7459a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) { 7469a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING); 7479a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString); 7489a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } 749e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 750e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mReplyFromAccount == null) { 751e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraft != null) { 752e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft); 753e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (mRefMessage != null) { 754e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage); 755e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 75662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 75762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mReplyFromAccount == null) { 75862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 759cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira mAccount.name, mAccount.name, true, false); 76062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 7619a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 76262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.setCurrentAccount(mReplyFromAccount); 7639a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 76462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mFromSpinner.getCount() > 1) { 765a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // If there is only 1 account, just show that account. 766a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // Otherwise, give the user the ability to choose which account to 76762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // send mail from / save drafts to. 76862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromStatic.setVisibility(View.GONE); 769a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 77062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinnerWrapper.setVisibility(View.VISIBLE); 771a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } else { 772a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStatic.setVisibility(View.VISIBLE); 773a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 774a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromSpinnerWrapper.setVisibility(View.GONE); 775a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } 77646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 77746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 77862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) { 77962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (refMessage.accountUri != null) { 78062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // This must be from combined inbox. 78162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 78262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 78362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.account.uri.equals(refMessage.accountUri)) { 78462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 78562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 78662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 78762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return null; 78862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 78962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getReplyFromAccount(account, refMessage); 79062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 79162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 79262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 79362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 79462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Given an account and which email address the message was sent to, 79562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * return who the message should be sent from. 79662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param account Account in which the message arrived. 79762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param sentTo Email address to which the message was sent. 79862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @return the address from which to reply. 79962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 80062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) { 80162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // First see if we are supposed to use the default address or 80262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // the address it was sentTo. 803326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (mCachedSettings.forceReplyFromDefault) { 80462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getDefaultReplyFromAccount(account); 80562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 80689bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira // If we aren't explicitly told which account to look for, look at 80762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // all the message recipients and find one that matches 80862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // a custom from or account. 80962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<String> allRecipients = new ArrayList<String>(); 8105ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp allRecipients.addAll(Arrays.asList(refMessage.getToAddresses())); 8115ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp allRecipients.addAll(Arrays.asList(refMessage.getCcAddresses())); 81262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getMatchingRecipient(account, allRecipients); 81362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 81462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 81562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 81662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 81762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Compare all the recipients of an email to the current account and all 81862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * custom addresses associated with that account. Return the match if there 81962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * is one, or the default account if there isn't. 82062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 82162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) { 82262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // Tokenize the list and place in a hashmap. 82362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount matchingReplyFrom = null; 82462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira Rfc822Token[] tokens; 82562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira HashSet<String> recipientsMap = new HashSet<String>(); 82662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (String address : sentTo) { 82762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira tokens = Rfc822Tokenizer.tokenize(address); 82862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (int i = 0; i < tokens.length; i++) { 82962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira recipientsMap.add(tokens[i].getAddress()); 83062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 83162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 83262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 83362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira int matchingAddressCount = 0; 83462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> customFroms; 8351617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang customFroms = account.getReplyFroms(); 8361617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang if (customFroms != null) { 8371617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang for (ReplyFromAccount entry : customFroms) { 8381617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang if (recipientsMap.contains(entry.address)) { 8391617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang matchingReplyFrom = entry; 8401617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang matchingAddressCount++; 84162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 84262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 84362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 84462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (matchingAddressCount > 1) { 84562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = getDefaultReplyFromAccount(account); 84662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 84762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return matchingReplyFrom; 84862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 84962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 85062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getDefaultReplyFromAccount(Account account) { 85162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 85262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 85362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.isDefault) { 85462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 85562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 85662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 857cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name, 858cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira true, false); 85962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 86062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 861e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) { 862e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira String sender = msg.from; 86362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount replyFromAccount = null; 86462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 86562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(account.name, sender)) { 86662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 867cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira mAccount.name, mAccount.name, true, false); 86862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 86962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount fromAccount : replyFromAccounts) { 87062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(fromAccount.name, sender)) { 87162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = fromAccount; 87262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira break; 87362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 87462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 87562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 87662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return replyFromAccount; 87762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 87862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 87946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 880b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.compose).setVisibility(View.VISIBLE); 881a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 8828e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 8838e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 8848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 8858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 8867b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 88793b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment); 888cd0b0b950efebfc3964334067747b97e61c4f027mindyp if (mPhotoAttachmentsButton != null) { 889cd0b0b950efebfc3964334067747b97e61c4f027mindyp mPhotoAttachmentsButton.setOnClickListener(this); 890cd0b0b950efebfc3964334067747b97e61c4f027mindyp } 89193b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp mVideoAttachmentsButton = findViewById(R.id.add_video_attachment); 892cd0b0b950efebfc3964334067747b97e61c4f027mindyp if (mVideoAttachmentsButton != null) { 893cd0b0b950efebfc3964334067747b97e61c4f027mindyp mVideoAttachmentsButton.setOnClickListener(this); 894cd0b0b950efebfc3964334067747b97e61c4f027mindyp } 895818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 896818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 897818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 89882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 89982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 9006349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 90162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp mSubject.setOnEditorActionListener(this); 90246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 90346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 904433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView = (EditText) findViewById(R.id.body); 9051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 9062eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 907eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 9085a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 909326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 910326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 91162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp @Override 91262d3ec7f251f6f9a96a859a2702916d07f30a04amindyp public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) { 91362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp if (action == EditorInfo.IME_ACTION_DONE) { 91462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp focusBody(); 91562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp return true; 91662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp } 91762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp return false; 91862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp } 91962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp 920e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira protected TextView getBody() { 921e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mBodyView; 922e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 923e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 924e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 925e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public Account getFromAccount() { 926e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mReplyFromAccount != null && mReplyFromAccount.account != null ? 927e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira mReplyFromAccount.account : mAccount; 928e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 929e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 930cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private void clearChangeListeners() { 931cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mSubject.removeTextChangedListener(this); 932cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBodyView.removeTextChangedListener(this); 933cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mTo.removeTextChangedListener(mToListener); 934cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCc.removeTextChangedListener(mCcListener); 935cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBcc.removeTextChangedListener(mBccListener); 936cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mFromSpinner.setOnAccountChangedListener(null); 937cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mAttachmentsView.setAttachmentChangesListener(null); 938cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 939cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira 94075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 94175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 94275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 94375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 94475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 94575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 946cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mToListener == null) { 947cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mToListener = new RecipientTextWatcher(mTo, this); 948cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 949cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mTo.addTextChangedListener(mToListener); 950cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mCcListener == null) { 951cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCcListener = new RecipientTextWatcher(mCc, this); 952cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 953cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCc.addTextChangedListener(mCcListener); 954cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mBccListener == null) { 955cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBccListener = new RecipientTextWatcher(mBcc, this); 956cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 957cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBcc.addTextChangedListener(mBccListener); 95875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 959818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 96075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 96175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 962326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private void initActionBar(int action) { 963326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = action; 964eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 965e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar == null) { 966e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return; 967e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 968326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (action == ComposeActivity.COMPOSE) { 969eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 970eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 971326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 972eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 973326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 974326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 975326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 976eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 977eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 978326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira switch (action) { 979326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 980eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 981326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 982326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 983eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 984326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 985326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 986eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 987326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 988326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 9896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 990fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 991fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 992fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 9936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 9946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 99546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void initFromRefMessage(int action, String recipientAddress) { 99696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira setFieldsFromRefMessage(action, recipientAddress); 99796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira if (mRefMessage != null) { 99896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // CC field only gets populated when doing REPLY_ALL. 99996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // BCC never gets auto-populated, unless the user is editing 100096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // a draft with one. 100129a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) { 100296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira mCcBccView.show(false, true, false); 100396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 100496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 100596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira updateHideOrShowCcBcc(); 100696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 100796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 100896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira private void setFieldsFromRefMessage(int action, String recipientAddress) { 10098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 10108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 10118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 10128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 10138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initRecipientsFromRefMessage(recipientAddress, mRefMessage, action); 1015e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 10168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 10178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 10186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 1019c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 1020c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 1021e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromDraftMessage(Message message) { 1022bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook LogUtils.d(LOG_TAG, "Intializing draft from previous draft message"); 1023bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 1024bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 1025bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 1026bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 1027bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 1028bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final List<String> toAddresses = Arrays.asList(message.getToAddresses()); 1029bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 1030bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses); 1031bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addBccAddresses(Arrays.asList(message.getBccAddresses())); 10322421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (message.hasAttachments) { 10332421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira List<Attachment> attachments = message.getAttachments(); 10342421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira for (Attachment a : attachments) { 10355c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(a); 10362421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 10372421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1038cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira int quotedTextIndex = message.appendRefMessageContent ? 1039002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.quotedTextOffset : -1; 1040bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 1041002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence quotedText = null; 1042bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 1043752222d839d9afeb5c4665669eab81645e413495Mindy Pereira CharSequence htmlText = ""; 1044002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 1045752222d839d9afeb5c4665669eab81645e413495Mindy Pereira // Find the offset in the htmltext of the actual quoted text and strip it out. 1046752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml); 1047752222d839d9afeb5c4665669eab81645e413495Mindy Pereira if (quotedTextIndex > -1) { 1048752222d839d9afeb5c4665669eab81645e413495Mindy Pereira htmlText = Html.fromHtml(message.bodyHtml.substring(0, quotedTextIndex)); 1049752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedText = message.bodyHtml.subSequence(quotedTextIndex, 1050752222d839d9afeb5c4665669eab81645e413495Mindy Pereira message.bodyHtml.length()); 1051752222d839d9afeb5c4665669eab81645e413495Mindy Pereira } 10521a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira } else { 10531a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira htmlText = Html.fromHtml(message.bodyHtml); 1054002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1055002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(htmlText); 1056bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 1057752222d839d9afeb5c4665669eab81645e413495Mindy Pereira final String body = message.bodyText; 1058752222d839d9afeb5c4665669eab81645e413495Mindy Pereira final CharSequence bodyText = !TextUtils.isEmpty(body) ? 1059752222d839d9afeb5c4665669eab81645e413495Mindy Pereira (quotedTextIndex > -1 ? 1060752222d839d9afeb5c4665669eab81645e413495Mindy Pereira message.bodyText.substring(0, quotedTextIndex) : message.bodyText) 1061752222d839d9afeb5c4665669eab81645e413495Mindy Pereira : ""; 1062002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 1063752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex) 1064752222d839d9afeb5c4665669eab81645e413495Mindy Pereira : null; 1065002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1066002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(bodyText); 1067002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1068002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1 && quotedText != null) { 10693971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward); 1070bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1071bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1072bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 10738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 10748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 10758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 10768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 10778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 10788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 10798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 10808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 10818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 10828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 10838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromExtras(Intent intent) { 10848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 10858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 10868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 10878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 10888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 10898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 10908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 10910b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira if (!mAccount.composeIntentUri.equals(dataUri)) { 10928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 10938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 10948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 1095dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(toText, ","))); 10968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 11028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 11038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 11048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 11068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 11078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 11088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 11108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 11118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 11128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 11158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 11168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 11178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 11208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 11218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 11228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 1123dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(value, ","))); 11248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 1125dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null); 11268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 1127dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addBccAddresses(Arrays.asList(TextUtils.split(value, ","))); 11288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 11298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 11308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 11318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 11328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 11378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 11388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 11398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 11408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 11418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1143e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 1144e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 11458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 11468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 1147a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // TODO: handle the case where there are spaces in the display name as 1148a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>" 1149a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // as they could be encoded ambiguously. 11508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 11518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 11528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 11538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String replacePlus = s.replace("+", "%2B"); 1154a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira try { 1155a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME); 1156a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } catch (IllegalArgumentException e) { 1157a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 1158a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s); 1159a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } else { 1160a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 1161a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 1162a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira return null; 1163a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 11648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 11678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 11688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 11698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 11708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 11718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 11728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 11748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 11758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 11768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 11778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 11788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 11798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 11808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 11818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 11828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 11838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1184a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (!TextUtils.isEmpty(to)) { 1185a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira addToAddresses(Arrays.asList(TextUtils.split(to, ","))); 1186a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 11878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 11888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 11898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 11908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 11918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 11928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 11968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 11978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 11988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 11998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 12008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 12028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 12038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 12058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 12068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 12078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME)); 12088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 12098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 12108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 12118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 12158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 12168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 12178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME), 12188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 12198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 12208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 12218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1225bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira @VisibleForTesting 1226bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira protected void initAttachments(Message refMessage) { 1227434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei addAttachments(refMessage.getAttachments()); 1228434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1229434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei 1230434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei public long addAttachments(List<Attachment> attachments) { 1231434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei long size = 0; 1232434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei AttachmentFailureException error = null; 1233434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei for (Attachment a : attachments) { 1234434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei try { 1235434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei size += mAttachmentsView.addAttachment(mAccount, a); 1236434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } catch (AttachmentFailureException e) { 1237434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei error = e; 1238434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1239434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1240434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei if (error != null) { 1241434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei LogUtils.e(LOG_TAG, error, "Error adding attachment"); 1242434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei if (attachments.size() > 1) { 1243434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(R.string.too_large_to_attach_multiple); 1244434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } else { 1245434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(error.getErrorRes()); 1246434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 12473cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 1248434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei return size; 12493cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 12503cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira 12513cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira /** 12523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * When an attachment is too large to be added to a message, show a toast. 12533cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * This method also updates the position of the toast so that it is shown 12543cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * clearly above they keyboard if it happens to be open. 12553cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira */ 1256434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei private void showAttachmentTooBigToast(int errorRes) { 1257434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei String maxSize = AttachmentUtils.convertToHumanReadableSize( 1258434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), mAccount.settings.getMaxAttachmentSize()); 1259434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getString(errorRes, maxSize)); 12603cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 12613cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira 1262434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei private void showErrorToast(String message) { 1263434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG); 1264434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei t.setText(message); 12653cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira t.setGravity(Gravity.CENTER_HORIZONTAL, 0, 12663cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset)); 12673cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira t.show(); 1268eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1269eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1270f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 127103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook Bundle extras = intent.getExtras(); 127203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook if (extras == null) { 127303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook extras = Bundle.EMPTY; 127403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook } 1275f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 1276f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 1277f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 1278f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 1279f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 1280f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 1281f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 1282f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1283f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 12845c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 1285f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1286f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1287434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1288f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1289f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1290f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1291f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1292f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) { 1293f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 1294f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1295f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 12965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 1297f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1298f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1299434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1300f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1301f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1302f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1303f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1304f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND_MULTIPLE.equals(action) 1305f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook && extras.containsKey(Intent.EXTRA_STREAM)) { 1306f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); 1307434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei ArrayList<Attachment> attachments = new ArrayList<Attachment>(); 1308f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (Parcelable uri : uris) { 1309f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 1310434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri)); 1311f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1312f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1313434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei String maxSize = AttachmentUtils.convertToHumanReadableSize( 1314434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), 1315434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei mAccount.settings.getMaxAttachmentSize()); 1316434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getString(R.string.generic_attachment_problem, maxSize)); 1317f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1318f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1319434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei totalSize += addAttachments(attachments); 1320f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1321f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1322f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 1323f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 1324f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 1325f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1326f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1327f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1328f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1329f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1330e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initQuotedTextFromRefMessage(Message refMessage, int action) { 1331e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) { 13329932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 13339932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 133446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 133546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 133646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 1337ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1338326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean ccVisible = mCcBccView.isCcVisible(); 1339326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean bccVisible = mCcBccView.isBccVisible(); 1340ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1341326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (!ccVisible || !bccVisible) { 1342ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 1343326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label 1344ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1345ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1346cd0b0b950efebfc3964334067747b97e61c4f027mindyp mCcBccButton.setVisibility(View.INVISIBLE); 1347ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1348ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 134946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 135046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1351a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira private void showCcBcc(Bundle state) { 1352326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (state != null && state.containsKey(EXTRA_SHOW_CC)) { 1353326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showCc = state.getBoolean(EXTRA_SHOW_CC); 1354326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC); 1355326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (showCc || showBcc) { 1356326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccView.show(false, showCc, showBcc); 1357326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1358326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1359326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1360326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira 1361013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 1362013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 1363013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 1364013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 1365013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 13662421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null); 13672421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 13682421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira 13695c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Uri contentUri) { 13705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang if (contentUri == null) { 13712421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira return; 13722421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1373013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 13745c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri)); 13755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } catch (AttachmentFailureException e) { 13765c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1377434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getResources().getString( 1378434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei e.getErrorRes(), 1379434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei AttachmentUtils.convertToHumanReadableSize( 1380434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), mAccount.settings.getMaxAttachmentSize()))); 13815c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 13825c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 13835c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang 13845c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Attachment attachment) { 13855c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang try { 1386434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei long size = mAttachmentsView.addAttachment(mAccount, attachment); 13879932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 13889932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 13899932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 1390013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 13919932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 13929932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1393434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1394013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1395013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1396013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 13973ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initRecipientsFromRefMessage(String recipientAddress, Message refMessage, 139846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action) { 13994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 14004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 14014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 14024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 140333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira initReplyRecipients(mAccount.name, refMessage, action); 14044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1406818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 14073ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initReplyRecipients(String account, Message refMessage, int action) { 14084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // This is the email address of the current user, i.e. the one composing 14094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the reply. 14104a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String accountEmail = Address.getEmailAddress(account).getAddress(); 14111469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira String fromAddress = getAddress(refMessage.from); 14125ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp String[] sentToAddresses = refMessage.getToAddresses(); 14133ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String replytoAddress = refMessage.replyTo; 1414a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 14154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 14174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 14184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 1419a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 1420a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 14213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 14221469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira sentToAddresses); 1423a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 1424a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 14254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 14263ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 14279b18a9a10538418f0280380e81452c52f5ce2542Mindy Pereira sentToAddresses); 1428154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 14294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addRecipients(accountEmail, ccAddresses, sentToAddresses); 14305ed6311d6beb968e83585a43d7cdf5909e0a2cf6mindyp addRecipients(accountEmail, ccAddresses, refMessage.getCcAddresses()); 14314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 14324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14351469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira private String getAddress(String toParse) { 14361469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira if (!TextUtils.isEmpty(toParse)) { 14371469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(toParse); 14381469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira if (tokens.length > 0) { 14391469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira return tokens[0].getAddress(); 14401469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 14411469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 14421469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira return ""; 14431469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 14441469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira 14454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 14464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 14474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 14508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 14518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 14524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1454bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 1455bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 1456bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1457bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 14584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 14594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 14604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 14614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 14624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 14648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 14658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 14668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 14674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 14684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 14718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 14728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 14738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 14748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 14758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 14768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 14778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 14788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 14798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) { 14864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira HashSet<String> hash = new HashSet<String>(); 14874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (Rfc822Token[] tokens : list) { 14884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 14894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 14904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 14934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 14944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 14964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 14974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 14984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 14994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 15004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 15014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 15034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 15064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 15074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 15084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 15094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addAddressToList(String address, RecipientEditTextView list) { 15134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 15144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 15154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 15174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 15194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 15204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 15244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected Collection<String> initToRecipients(String account, String accountEmail, 15253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String senderAddress, String replyToAddress, String[] inToAddresses) { 15264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 15274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 15284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 15294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 15304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 15314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 15323ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira if (!TextUtils.isEmpty(replyToAddress)) { 15333ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 15344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 1535cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira if (!recipientMatchesThisAccount(account, senderAddress)) { 15361469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira toAddresses.add(senderAddress); 15371469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } else { 15381469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira // This happens if the user replies to a message they originally 15391883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira // wrote. In this case, "reply" really means "re-send," so we 15401883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira // target the original recipients. This works as expected even 15411883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira // if the user sent the original message to themselves. 15421469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira toAddresses.addAll(Arrays.asList(inToAddresses)); 15431469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 15444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 15464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1548cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira private void addRecipients(String accountAddress, Set<String> recipients, String[] addresses) { 15494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String email : addresses) { 1550cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira // Do not add this account, or any of its custom from addresses, to 1551cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira // the list of recipients. 15524a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 1553cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira if (!recipientMatchesThisAccount(accountAddress, recipientAddress)) { 15544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 15554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 155746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 155846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1559cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira /** 1560cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * A recipient matches this account if it has the same address as the 1561cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * currently selected account OR one of the custom from addresses associated 1562cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * with the currently selected account. 1563cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @param accountAddress currently selected account 1564cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @param recipientAddress address we are comparing with the currently selected account 1565cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @return 1566cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira */ 1567cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira protected boolean recipientMatchesThisAccount(String accountAddress, String recipientAddress) { 1568cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira return accountAddress.equalsIgnoreCase(recipientAddress) 1569cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira || ReplyFromAccount.isCustomFrom(recipientAddress, 1570cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira mFromSpinner.getReplyFromAccounts()); 1571cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira } 1572cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira 15733ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void setSubject(Message refMessage, int action) { 15743ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String subject = refMessage.subject; 157546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 157646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 157746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 157846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 157946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 158046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.forward_subject_label); 158146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 158246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.reply_subject_label); 158346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 158446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 158546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 1586c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira if (!TextUtils.isEmpty(subject) 1587c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira && subject.toLowerCase().startsWith(prefix.toLowerCase())) { 158846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 158946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 159046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = String 159146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira .format(getString(R.string.formatted_subject), prefix, subject); 159246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 159346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mSubject.setText(correctedSubject); 159446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 159546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1596818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 1597818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 1598818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 1599818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 1600eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1601eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1602818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 1603679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 1604c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira view.setTokenizer(new Rfc822Tokenizer()); 160582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 1606679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook final String accountName = mAccount.name; 160733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 160833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 1609c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira if (offset > -1) { 161033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira account = account.substring(accountName.indexOf("@") + 1); 1611c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 161282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 1613c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 161482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 16158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 16168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 16178e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 16188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 16198e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira int id = v.getId(); 16208e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira switch (id) { 1621a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira case R.id.add_cc_bcc: 16228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Verify that cc/ bcc aren't showing. 16238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Animate in cc/bcc. 1624a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira showCcBccViews(); 16258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira break; 1626cd0b0b950efebfc3964334067747b97e61c4f027mindyp case R.id.add_photo_attachment: 1627cd0b0b950efebfc3964334067747b97e61c4f027mindyp doAttach(MIME_TYPE_PHOTO); 1628cd0b0b950efebfc3964334067747b97e61c4f027mindyp break; 1629cd0b0b950efebfc3964334067747b97e61c4f027mindyp case R.id.add_video_attachment: 1630cd0b0b950efebfc3964334067747b97e61c4f027mindyp doAttach(MIME_TYPE_VIDEO); 1631cd0b0b950efebfc3964334067747b97e61c4f027mindyp break; 16328e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 16338e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1634b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1635b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1636b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 1637b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira super.onCreateOptionsMenu(menu); 1638b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Don't render any menu items when there are no accounts. 1639b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 1640b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return true; 1641b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1642b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1643b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 164482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 164582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 16463ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem helpItem = menu.findItem(R.id.help_info_menu_item); 16473ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item); 16483ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (helpItem != null) { 16493ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira helpItem.setVisible(mAccount != null 16503ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT)); 16513ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 16523ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (sendFeedbackItem != null) { 16533ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira sendFeedbackItem.setVisible(mAccount != null 16543ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK)); 16553ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 1656b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1657b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1658b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1659b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1660ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 1661ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 1662818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 1663ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1664ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 1665ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 1666ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 1667ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 1668ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 1669ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1670ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1671ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 1672ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1673ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 167475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (mSave != null) { 167575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSave.setEnabled(shouldSave()); 167675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 1677ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 1678ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1679ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1680ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 1681b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 1682b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira int id = item.getItemId(); 168375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 1684b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira switch (id) { 16852db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira case R.id.add_photo_attachment: 16862db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira doAttach(MIME_TYPE_PHOTO); 16872db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira break; 16882db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira case R.id.add_video_attachment: 16892db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira doAttach(MIME_TYPE_VIDEO); 16907b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira break; 1691ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira case R.id.add_cc_bcc: 1692ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira showCcBccViews(); 1693b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira break; 169433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.save: 169548e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira doSave(true); 169633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 169733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.send: 169833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira doSend(); 169975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira break; 1700efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira case R.id.discard: 1701efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira doDiscard(); 1702efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira break; 17031f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.settings: 17041f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira Utils.showSettings(this, mAccount); 17051f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 1706fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case android.R.id.home: 1707daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook onAppUpPressed(); 1708fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1709fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.help_info_menu_item: 171030745b6e9c4d280ac578d1186fbc0cec9bd2a838Paul Westbrook Utils.showHelp(this, mAccount, getString(R.string.compose_help_context)); 1711fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1712fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.feedback_menu_item: 171317beb0b8aee78a39a2094a48ba7f55a602f701cbPaul Westbrook Utils.sendFeedback(this, mAccount, false); 1714fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 171575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira default: 171675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira handled = false; 171733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 1718b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1719b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 1720b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1721326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1722b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira @Override 1723b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira public void onBackPressed() { 1724b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // If we are showing the wait fragment, just exit. 1725b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (getWaitFragment() != null) { 1726b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 1727b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 1728b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira super.onBackPressed(); 1729b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1730b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1731b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 1732daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private void onAppUpPressed() { 1733daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (mLaunchedFromEmail) { 1734daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // If this was started from Gmail, simply treat app up as the system back button, so 1735daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // that the last view is restored. 1736daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook onBackPressed(); 1737daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook return; 1738daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 1739daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 1740daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Fire the main activity to ensure it launches the "top" screen of mail. 1741daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Since the main Activity is singleTask, it should revive that task if it was already 1742daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // started. 17435ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira Folder defaultInbox = new Folder(); 17445ad02918f663bc52522a2505de985df9ef5ea347Mindy Pereira defaultInbox.uri = mAccount.settings.defaultInbox; 1745daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final Intent mailIntent = 174696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira Utils.createViewFolderIntent(defaultInbox, mAccount); 1747daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 1748daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 1749daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook Intent.FLAG_ACTIVITY_TASK_ON_HOME); 1750daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook startActivity(mailIntent); 1751daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook finish(); 1752daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 1753daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 175433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 17558aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira clearImeText(); 175682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira sendOrSaveWithSanityChecks(false, true, false); 175733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 175833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 175948e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira private void doSave(boolean showToast) { 176048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira // Clear the IME composing suggestions from the body and subject before saving. 17618aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira clearImeText(); 1762eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira sendOrSaveWithSanityChecks(true, showToast, false); 176348e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira } 176448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira 17658aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira private void clearImeText() { 17668aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira mBodyView.clearComposingText(); 17678aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira BaseInputConnection.removeComposingSpans(mBodyView.getEditableText()); 17688aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira mSubject.clearComposingText(); 17698aa913bd66109f7a4252dd07d10f73132ce7beedMindy Pereira BaseInputConnection.removeComposingSpans(mSubject.getEditableText()); 177082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 177182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1772e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1773e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public interface SendOrSaveCallback { 177482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 17757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 17767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 177782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 177882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 177982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1780e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1781e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveTask implements Runnable { 178282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 178382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 1784e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveCallback mSendOrSaveCallback; 1785e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1786e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveMessage mSendOrSaveMessage; 178782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 178882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 178982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira SendOrSaveCallback callback) { 179082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 179182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 179282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 179382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 179482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 179582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 179682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 17977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 179882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 179992551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount; 18007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 18017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 180282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 180382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 180482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 18057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) { 180682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 180782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 180882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 180982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 181092551d057965689f1952faeb06763f0762bc717fMindy Pereira if (selectedAccount.account.expungeMessageUri != null) { 181192551d057965689f1952faeb06763f0762bc717fMindy Pereira resolver.update(selectedAccount.account.expungeMessageUri, values, null, 1812eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira null); 1813cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1814cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 1815eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 181682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 181782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 181882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 181982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 182082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 182182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 182282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) { 18237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 182482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext.getContentResolver().update( 18257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri), 18267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues, null, null); 182782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } else { 18287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira ContentResolver resolver = mContext.getContentResolver(); 182992551d057965689f1952faeb06763f0762bc717fMindy Pereira Uri messageUri = resolver 183092551d057965689f1952faeb06763f0762bc717fMindy Pereira .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri 183192551d057965689f1952faeb06763f0762bc717fMindy Pereira : selectedAccount.account.sendMessageUri, 183292551d057965689f1952faeb06763f0762bc717fMindy Pereira sendOrSaveMessage.mValues); 18337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sendOrSaveMessage.mSave && messageUri != null) { 18347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Cursor messageCursor = resolver.query(messageUri, 18357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira UIProvider.MESSAGE_PROJECTION, null, null, null); 1836ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor != null) { 1837ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 1838ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor.moveToFirst()) { 1839ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // Broadcast notification that a new message has 1840ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // been allocated 1841ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 1842ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook new Message(messageCursor)); 1843ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 1844ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } finally { 1845ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook messageCursor.close(); 1846ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 18477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 18487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 184982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 185082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 18517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!sendOrSaveMessage.mSave) { 185282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 18537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 185482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 18557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 185682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 18577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 185882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 185982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 186082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 186182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 186282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 186382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Array of the outstanding send or save tasks. Access is synchronized 186482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // with the object itself 186582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /* package for testing */ 1866e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1867e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 186882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRequestId; 1869bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String mSignature; 1870b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private Account[] mAccounts; 187182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1872e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1873e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveMessage { 187492551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount mAccount; 187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 18763ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 1877e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1878e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final boolean mSave; 187982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 188082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 188192551d057965689f1952faeb06763f0762bc717fMindy Pereira public SendOrSaveMessage(ReplyFromAccount account, ContentValues values, 18823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String refMessageId, boolean save) { 188382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 188582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 188682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 188782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 188882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 188982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 189082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 189182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 189282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 189382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 189482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 189582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 189682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 189782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 189882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 189982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 190082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 190182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 190282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 190382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 190482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 190582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 190682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 190782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 190882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 190982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 191082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 191182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 191282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 191382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 191482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 191582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 191682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 191782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 191882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 191982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 192082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 192182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 192282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 192382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 192482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 192582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 192682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 192782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 192882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 192982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 193082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 193182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 193282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 193382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 193482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) { 1935e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira if (mValidator == null) { 1936e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira return; 1937e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira } 193882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (String email : to) { 193982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 194082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 194182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 194282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 194382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 194482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 194582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 194682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 194782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 194882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 194982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void showRecipientErrorDialog(String message) { 195082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Only 1 invalid recipients error dialog should be allowed up at a 195182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // time. 195282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mRecipientErrorDialog != null) { 195382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog.dismiss(); 195482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 195582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle( 195682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.recipient_error_dialog_title) 195782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 195882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setPositiveButton( 195982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.ok, new Dialog.OnClickListener() { 19600bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 196182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 196282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // after the user dismisses the recipient error 196382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // dialog we want to make sure to refocus the 196482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // recipient to field so they can fix the issue 196582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // easily 196682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mTo != null) { 196782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTo.requestFocus(); 196882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 196982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = null; 197082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 197182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira }).show(); 197282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 197382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 197482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 197582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 197682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 197782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 1978eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 197982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 198082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 198182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 198282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 198382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 198482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 198582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 198682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 198782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 19887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 198982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 199082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 199182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 199282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 1993a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira // AND there is actually something in the draft to save. 1994d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang return (mTextChanged || mAttachmentsChanged || mReplyFromChanged) 1995a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira && !isBlank(); 199682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 199782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 199882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 199982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 2000bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 200182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 200282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 200382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 200482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 2005bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 2006bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 2007bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 2008bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 2009bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 2010bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2011bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2012bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 2013bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 2014bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 2015bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2016bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 2017bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 2018bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2019bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2020bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 2021bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 2022bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 2023bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 2024bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2025bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 2026bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 2027bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 2028bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 2029bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 2030bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 2031bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 2032bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 2033bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2034bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 203582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 203682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 203782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 203882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 203982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 204082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 204182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 204282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 2043eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 204482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 204533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 204633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 204782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 2048181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param body 2049181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 2050181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 2051181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 2052181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2053181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 2054181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira final boolean orientationChanged) { 2055181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 2056181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Editable body = mBodyView.getEditableText(); 2057181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 2058181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 2059181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 2060181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 2061181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 2062181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 2063181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2064181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2065181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 2066181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 2067181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 2068181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 2069181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 2070181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2071181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2072181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 2073181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2074181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 2075181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 2076181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 2077181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2078181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2079181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 2080181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 2081181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 2082181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 2083181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 2084181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 2085181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2086181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2087181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 20880bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 2089181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onClick(DialogInterface dialog, int which) { 2090181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged); 2091181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2092181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 2093181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2094181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 2095181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2096181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 2097181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 2098181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean emptyBody = TextUtils.getTrimmedLength(body) == 0; 2099181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2100181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 2101181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 2102181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 2103181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 2104181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2105181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 2106181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 2107181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 2108181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 2109181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener); 2110181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2111181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2112181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2113181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 2114181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener); 2115181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2116181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2117181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2118181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 2119181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 2120181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message, listener); 2121181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2122181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2123181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2124181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2125181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(body, save, showToast, false); 2126181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2127181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2128181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2129181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2130181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 2131181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 21325c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang * 2133181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 2134181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2135181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 2136181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 2137181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2138181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2139181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2140181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 2141181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 2142181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 2143181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2144181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 2145181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 2146181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2147181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2148181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) { 2149181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendConfirmDialog != null) { 2150181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog.dismiss(); 2151181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = null; 2152181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2153181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId) 2154181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setTitle(R.string.confirm_send_title) 2155181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 2156181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setPositiveButton(R.string.send, listener) 21576edd597b1a6628660284f03442cce1f193af66dcMindy Pereira .setNegativeButton(R.string.cancel, this) 21586edd597b1a6628660284f03442cce1f193af66dcMindy Pereira .show(); 2159181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2160181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2161181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2162181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 2163181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 2164181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 2165181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2166181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 2167181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 2168181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2169181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2170181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2171181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 2172181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 2173181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 2174181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2175181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 2176181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 2177181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 2178181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 2179181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2180181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2181181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 2182e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount, 218305b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook Message message, final Message refMessage, Spanned body, final CharSequence quotedText, 218405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) { 218529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira ContentValues values = new ContentValues(); 218629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 2187c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira String refMessageId = refMessage != null ? refMessage.uri.toString() : ""; 2188c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira 2189e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putToAddresses(values, message.getToAddresses()); 2190e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCcAddresses(values, message.getCcAddresses()); 2191e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putBccAddresses(values, message.getBccAddresses()); 219229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 2193e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCustomFromAddress(values, message.from); 219492551d057965689f1952faeb06763f0762bc717fMindy Pereira 2195e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putSubject(values, message.subject); 219629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira String htmlBody = Html.toHtml(body); 219705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook 219829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 219929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 220029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 2201e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 2202e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 2203e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 2204e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 220555271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook final int quoteStartPos = fullBody.length() + pos; 220655271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook fullBody.append(text); 220755271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook MessageModification.putQuoteStartPos(values, quoteStartPos); 220812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 2209e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 221029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 2211e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 2212e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 2213e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 2214e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 221529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 221629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 2217002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = getDraftType(composeMode); 221812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 2219c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (refMessage != null) { 2220c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyHtml)) { 2221c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 2222c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 2223c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyText)) { 2224c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 2225c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 2226c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } else { 2227c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 2228c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 2229c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira } 2230e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putAttachments(values, message.getAttachments()); 223112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 223212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 223312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 223592551d057965689f1952faeb06763f0762bc717fMindy Pereira SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount, 2236181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira values, refMessageId, save); 2237181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback); 223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2239181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2241181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 2242181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 2243181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 224482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2245181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 2246181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 224782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2248002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira private static int getDraftType(int mode) { 2249002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = -1; 2250002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira switch (mode) { 2251002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.COMPOSE: 2252002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.COMPOSE; 2253002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2254002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY: 2255002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY; 2256002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2257002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY_ALL: 2258002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY_ALL; 2259002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2260002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.FORWARD: 2261002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.FORWARD; 2262002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2263002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2264002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira return draftType; 2265002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2266002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira 2267181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void sendOrSave(Spanned body, boolean save, boolean showToast, 2268181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean orientationChanged) { 2269181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 2270181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 22713ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook if (ActivityManager.isUserAMonkey()) { 2272181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 2273181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 227482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2275181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 2276181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 2277181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 2278181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 2279181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 2280181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 2281181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 2282181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 228382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2284181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 228582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 228682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 22870bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 228882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 2289181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 2290181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 2291181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 2292181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 2293181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 2294181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 2295181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2296181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2297181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 2298181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2299181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 2300181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 2301181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2302181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 230382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 23040bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 23057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 23067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 2307181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 2308181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 2309181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 23107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 23117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 23127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2313181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 2314181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 2315181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2316181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 23177ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 2318181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2319181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 232082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 23210bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 23227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 23237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 23247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 23257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 23267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 232782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 23280bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 23297ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 233047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // Update the last sent from account. 233147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (mAccount != null) { 233247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString()); 233347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 23347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 23357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 23367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 23377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 23387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 23397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 23407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 23417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 23427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 23437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 234482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 23457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 23467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 23477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 23487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 23497ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 23507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 235182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 23527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 23537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 23547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 23557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 23567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 23577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 23587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 23597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 2361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Get the selected account if the from spinner has been setup. 236392551d057965689f1952faeb06763f0762bc717fMindy Pereira ReplyFromAccount selectedAccount = mReplyFromAccount; 2364181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String fromAddress = selectedAccount.name; 2365181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (selectedAccount == null || fromAddress == null) { 2366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // We don't have either the selected account or from address, 2367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // use mAccount. 236892551d057965689f1952faeb06763f0762bc717fMindy Pereira selectedAccount = mReplyFromAccount; 2369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira fromAddress = mAccount.name; 2370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 2373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2379e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message msg = createMessage(mReplyFromAccount, getMode()); 238005b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body, 238105b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mQuotedTextView.getQuotedTextIfIncluded(), callback, 238212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira mSendSaveTaskHandler, save, mComposeMode); 2383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mRecipient != null && mRecipient.equals(mAccount.name)) { 2385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRecipient = selectedAccount.name; 2386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2387b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(selectedAccount.account); 2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 2398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 2399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 2403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 2405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 2410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 2411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 2412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 2414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 2415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 241682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 24172db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private void doAttach(String type) { 2418013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 2419013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 2420d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 24212db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira i.setType(type); 2422013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 2423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 2424181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 2425013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 2426013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 2427ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 2428a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 2429ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 2430cd0b0b950efebfc3964334067747b97e61c4f027mindyp mCcBccButton.setVisibility(View.INVISIBLE); 2431ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2432ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2433ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 2434326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2435326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 2436a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 2437326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 2438326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 2439326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 2440326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 2441326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 2442326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 2443326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2444cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira clearChangeListeners(); 2445a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 2446154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 2447ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mDraft == null && mRefMessage != null) { 244896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira setFieldsFromRefMessage(mComposeMode, mAccount.name); 24498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 2450ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showCc = false; 2451ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showBcc = false; 2452ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mDraft != null) { 2453ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Following desktop behavior, if the user has added a BCC 2454ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // field to a draft, we show it regardless of compose mode. 2455ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira showBcc = !TextUtils.isEmpty(mDraft.bcc); 2456ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Use the draft to determine what to populate. 2457ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // If the Bcc field is showing, show the Cc field whether it is populated or not. 2458ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira showCc = showBcc || (!TextUtils.isEmpty(mDraft.cc) && mComposeMode == REPLY_ALL); 2459ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } else if (mRefMessage != null) { 2460ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira showCc = mComposeMode == REPLY_ALL && !TextUtils.isEmpty(mRefMessage.cc); 2461ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } 2462ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 2463a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 2464ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira updateHideOrShowCcBcc(); 2465cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira initChangeListeners(); 2466326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 2467326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2468326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2469b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira @VisibleForTesting 2470b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira protected void resetMessageForModeChange() { 2471154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 2472154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 2473154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 2474154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 2475154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 2476154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 2477154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 2478154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 2479154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 2480154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 2481154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 2482154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 2483154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2484154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 2485154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 2486154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 2487154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 2488154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 2489154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 2490154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2491154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2492154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2493326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 2494326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2495326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 2496326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2497326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 2498326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 2499326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 2500326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2501326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2502326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 2503326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 2504326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 2505326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2506326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 2507326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2508326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2509326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2510326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 2511326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 2512326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 2513326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2514326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 2515326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 2516326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2517326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 251846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 251946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 252046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 252146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 252240882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(false); 252340882430c874ff29890ec6fa31f7649788cbc470mindyp mTo.requestFocus(); 252446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 252546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 252646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 252746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 252846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 252946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 253046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 253146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 253246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 253346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 2534eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 253546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 253646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 253746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 253846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 253946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 254046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 254146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 254246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 254346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 2544bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 254546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 254646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 254746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 254846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 2549eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 2550bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 2551bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 2552bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2553bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2554bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2555bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 2556b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira String newSignature = mCachedSettings != null ? mCachedSettings.signature : null; 2557433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira boolean hasFocus = mBodyView.hasFocus(); 2558b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.equals(newSignature, mSignature)) { 2559b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mSignature = newSignature; 2560b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.isEmpty(mSignature) 2561b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira && getSignatureStartPosition(mSignature, 2562b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.getText().toString()) < 0) { 2563b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira // Appending a signature does not count as changing text. 2564b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.removeTextChangedListener(this); 2565b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 2566b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.addTextChangedListener(this); 2567b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira } 2568433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (hasFocus) { 2569433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 2570433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 2571bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2572bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2573bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2574bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 2575bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 2576bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 2577bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 2578bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2579bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 258046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 25811a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 25825a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 25835a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 258492551d057965689f1952faeb06763f0762bc717fMindy Pereira mReplyFromAccount = mFromSpinner.getCurrentAccount(); 258592551d057965689f1952faeb06763f0762bc717fMindy Pereira if (!mAccount.equals(mReplyFromAccount.account)) { 2586b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(mReplyFromAccount.account); 2587b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook 2588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 2589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 2590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 2592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 2593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 2595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 259682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 25971a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 259882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 259982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 260082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 260182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 260282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 260382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 260482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 260582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSend(boolean enabled) { 260682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSend != null) { 260782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend.setEnabled(enabled); 260882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 260982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 261082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 261182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 261282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Handles button clicks from any error dialogs dealing with sending 261382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * a message. 261482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 261582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 261682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 261782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira switch (which) { 261882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_POSITIVE: { 261982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira doDiscardWithoutConfirmation(true /* show toast */ ); 262082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 262182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 262282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_NEGATIVE: { 262382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If the user cancels the send, re-enable the send button. 262482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira enableSend(true); 262582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 262682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 262782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 262882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 262982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 263082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2631efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 2632efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text) 2633efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setPositiveButton(R.string.ok, this) 2634efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setNegativeButton(R.string.cancel, null) 2635efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .create().show(); 2636efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 263782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 263882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 263982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 264082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 264182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 264282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param showToast show "Message discarded" toast if true 264382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 264482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void doDiscardWithoutConfirmation(boolean showToast) { 26457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 264682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 264782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 2648b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 264978ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) { 2650cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 2651cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 26520bbc858506c95005f2840fa5dff495a9216d2665Marc Blank getContentResolver().delete(mDraft.uri, null, null); 2653cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 265482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 265582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 265682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 265782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 265882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 265982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 266082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 266182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 266282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (showToast) { 266382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Display a toast to let the user know 266482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 266582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 266682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 266782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 266882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 266982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 267082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 267182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2672eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 2673eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 2674eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 2675eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 2676eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 2677eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 2678eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2679eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2680eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 268148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira doSave(!mAddingAttachment /* show toast */); 2682eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2683eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2684eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2685eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 2686eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 2687eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 268840882430c874ff29890ec6fa31f7649788cbc470mindyp // If we are showing any attachments, make sure we have an upper 268940882430c874ff29890ec6fa31f7649788cbc470mindyp // divider. 269040882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 2691eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 2692eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 269375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 269440882430c874ff29890ec6fa31f7649788cbc470mindyp @Override 269540882430c874ff29890ec6fa31f7649788cbc470mindyp public void onAttachmentAdded() { 269640882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 269740882430c874ff29890ec6fa31f7649788cbc470mindyp mAttachmentsView.focusLastAttachment(); 269840882430c874ff29890ec6fa31f7649788cbc470mindyp } 269975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 270075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 270175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 270275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 27030bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 270475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 270575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 270675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 270775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 270875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 270975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 271075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 271175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 271275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 271375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 27140bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 271575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 271675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 271775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 271875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 271975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 272075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 272175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 272275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 272375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 272475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 272575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 272675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 272775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 272875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 272975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 273075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 273175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 273275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 273375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 273475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 273575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 273675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 273775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 273875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 273975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 274075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 274175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 274275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 274375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 274475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 274575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 274675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 274775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 274875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 274975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 275075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 275175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 275275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 275375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 275475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 275575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 275675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 275775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 275875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 275975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 276075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 276175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 276275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 276375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 276475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 276575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 276675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 276775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 276875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 276975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 277075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 277175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 277275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 277375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 277475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 277575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 277675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 277775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 277875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 277975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 278075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 278175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 278275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 278375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 278475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 278575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 278675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 278775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 278875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 278975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 279075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 279175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 279275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 279375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 2794e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 2795e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) { 2796e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (sTestSendOrSaveCallback != null && testCallback != null) { 2797e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira throw new IllegalStateException("Attempting to register more than one test callback"); 2798e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 2799e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira sTestSendOrSaveCallback = testCallback; 2800e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 2801bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira 2802bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira @VisibleForTesting 2803bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira protected ArrayList<Attachment> getAttachments() { 2804bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira return mAttachmentsView.getAttachments(); 2805bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira } 280696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 280796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 280896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public Loader<Cursor> onCreateLoader(int id, Bundle args) { 280996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira switch (id) { 281096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira case REFERENCE_MESSAGE_LOADER: 281196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null, 281296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira null, null); 2813b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case LOADER_ACCOUNT_CURSOR: 2814b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return new CursorLoader(this, MailAppProvider.getAccountsUri(), 2815b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira UIProvider.ACCOUNTS_PROJECTION, null, null, null); 281696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 281796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return null; 281896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 281996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 282096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 282196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 2822b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira int id = loader.getId(); 2823b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira switch (id) { 2824b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case REFERENCE_MESSAGE_LOADER: 2825b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (data != null && data.moveToFirst()) { 2826b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mRefMessage = new Message(data); 2827b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // We set these based on EXTRA_TO. 2828b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mRefMessage.to = null; 2829b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mRefMessage.from = null; 2830b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Intent intent = getIntent(); 2831b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 2832b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initFromRefMessage(action, mAccount.name); 2833b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishSetup(action, intent, null, true); 2834b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (action != FORWARD) { 2835b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira String to = intent.getStringExtra(EXTRA_TO); 2836b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (!TextUtils.isEmpty(to)) { 2837b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira clearChangeListeners(); 2838b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mTo.append(to); 2839b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initChangeListeners(); 2840b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2841b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2842b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 2843b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 284496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 2845b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 2846b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case LOADER_ACCOUNT_CURSOR: 2847b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (data != null && data.moveToFirst()) { 2848b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // there are accounts now! 2849b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Account account; 2850b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira ArrayList<Account> accounts = new ArrayList<Account>(); 2851b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira ArrayList<Account> initializedAccounts = new ArrayList<Account>(); 2852b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira do { 2853b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = new Account(data); 2854b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (account.isAccountIntialized()) { 2855b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initializedAccounts.add(account); 2856b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2857b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira accounts.add(account); 2858b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } while (data.moveToNext()); 2859b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (initializedAccounts.size() > 0) { 2860b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.wait).setVisibility(View.GONE); 2861b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR); 2862b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.compose).setVisibility(View.VISIBLE); 2863b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAccounts = accounts.toArray(new Account[initializedAccounts.size()]); 2864b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishCreate(); 2865b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira invalidateOptionsMenu(); 2866b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 2867b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Show "waiting" 2868b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = accounts.size() > 0 ? accounts.get(0) : null; 2869b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira showWaitFragment(account); 2870b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2871b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2872b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 2873b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2874b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2875b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 2876b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void showWaitFragment(Account account) { 2877b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira WaitFragment fragment = getWaitFragment(); 2878b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (fragment != null) { 2879b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragment.updateAccount(account); 288096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } else { 2881b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.wait).setVisibility(View.VISIBLE); 2882b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira replaceFragment(WaitFragment.newInstance(account, true), 2883b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT); 288496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 288596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 288696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 2887b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private WaitFragment getWaitFragment() { 2888b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT); 2889b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2890b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 2891b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private int replaceFragment(Fragment fragment, int transition, String tag) { 2892b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 2893b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.addToBackStack(null); 2894b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.setTransition(transition); 2895b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.replace(R.id.wait, fragment, tag); 2896b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira final int transactionId = fragmentTransaction.commitAllowingStateLoss(); 2897b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return transactionId; 2898b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2899b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 290096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 290196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public void onLoaderReset(Loader<Cursor> arg0) { 290296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // Do nothing. 290396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 290496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira}