ComposeActivity.java revision d90639004a3551d7fb7086f318d4c576d54d2b86
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/** 28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc. 38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License. 68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at 78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software 118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and 148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License. 158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */ 168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose; 188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar; 205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener; 215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity; 2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager; 2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog; 2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog; 252558b509117872e539a6eaeb72aa63425529d50bTony Mantlerimport android.app.DialogFragment; 26b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.Fragment; 27b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport android.app.FragmentTransaction; 2896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.app.LoaderManager; 296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver; 3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues; 316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context; 3296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.CursorLoader; 3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface; 346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent; 3596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereiraimport android.content.Loader; 3682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo; 377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor; 386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri; 398e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle; 4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler; 4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread; 423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor; 431ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable; 4482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns; 4546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable; 4682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html; 47ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString; 4882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned; 49c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils; 5082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher; 5146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token; 52c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 533cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity; 5462d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent; 55326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater; 56b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu; 57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater; 58b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem; 598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View; 608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener; 615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup; 62b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection; 6362d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo; 64326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 658e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 66433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText; 676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 68013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 697b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 70c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 715c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView; 725680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService; 735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R; 741ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView; 7540882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener; 769932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 775a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 7933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 8130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 825680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder; 8347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider; 843ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 8582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 8692551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount; 87181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 8830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 893ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 9012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 911ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview; 9283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity; 93fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity; 94b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment; 9592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 96434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils; 97febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask; 98b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 9930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 10030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 10146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 10282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 1034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 1048e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 1053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException; 1063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException; 1078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 1088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 10946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 110bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 11146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 11275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 11346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 11446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 1151c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 116bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 11782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 11846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 11946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 1202558b509117872e539a6eaeb72aa63425529d50bTony Mantler RespondInlineListener, TextWatcher, 121a990a715012379451344246c5156d29938f12886Alice Yang AttachmentAddedOrDeletedListener, OnAccountChangedListener, 122a990a715012379451344246c5156d29938f12886Alice Yang LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener, 123a990a715012379451344246c5156d29938f12886Alice Yang FeedbackEnabledActivity { 1246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 12515f505ba369523b6a3b3141221db9719c5e6db80mindyp protected static final int COMPOSE = -1; 12615f505ba369523b6a3b3141221db9719c5e6db80mindyp protected static final int REPLY = 0; 12715f505ba369523b6a3b3141221db9719c5e6db80mindyp protected static final int REPLY_ALL = 1; 12815f505ba369523b6a3b3141221db9719c5e6db80mindyp protected static final int FORWARD = 2; 12915f505ba369523b6a3b3141221db9719c5e6db80mindyp protected static final int EDIT_DRAFT = 3; 1306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 13296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira protected static final String EXTRA_ACTION = "action"; 1336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 134326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_CC = "showCc"; 135326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_BCC = "showBcc"; 1361623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private static final String EXTRA_RESPONDED_INLINE = "respondedInline"; 1371d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp private static final String EXTRA_SAVE_ENABLED = "saveEnabled"; 138a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira 1398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 147d27b6ea7fcc68b2af200158fab341c6e98727144mindyp protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString"; 1489a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 14962066e47fe69c33b60ed970e46809ba81d044064Mark Wei private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews"; 15062066e47fe69c33b60ed970e46809ba81d044064Mark Wei 1518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 1528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_TO = "to"; 1538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 1578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC }; 1588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 15982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 16082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 16182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 16282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 16382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 16482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 16582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 16682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 16782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 16882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 16982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 17082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 1711f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang // FIXME: values in this map are never read. 17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 1736349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1766349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 179daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook public static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 181e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String EXTRA_ATTACHMENTS = "attachments"; 182f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1835680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy /** If set, we will clear notifications for this folder. */ 1845680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder"; 1855680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy 1863ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 18736bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 188b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira // If this is a reply/forward then this extra will hold a uri we must query 189b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira // to get the original message. 190b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri"; 191434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei // If this is an action to edit an existing draft message, this extra will hold the 192bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 193bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 1944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 195b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 196013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 197013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 198013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 1998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 200e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 2018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 202e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount"; 203e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_REQUEST_ID = "requestId"; 204e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart"; 205176a1993ab15298de58f0cc988939b2cc1632689Paul Westbrook private static final String EXTRA_FOCUS_SELECTION_END = "focusSelectionEnd"; 206e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_MESSAGE = "extraMessage"; 20796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira private static final int REFERENCE_MESSAGE_LOADER = 0; 208b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private static final int LOADER_ACCOUNT_CURSOR = 1; 209a990a715012379451344246c5156d29938f12886Alice Yang private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2; 21047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount"; 211b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private static final String TAG_WAIT = "wait-fragment"; 2122db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private static final String MIME_TYPE_PHOTO = "image/*"; 2132db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private static final String MIME_TYPE_VIDEO = "video/*"; 2148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 2159f855d667e34fbf0d330845225c26956e540b819Andy Huang private static final String KEY_INNER_SAVED_STATE = "compose_state"; 2169f855d667e34fbf0d330845225c26956e540b819Andy Huang 21782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 21882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 21982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 22082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 221c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 222c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 223c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 2248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 2258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 2267b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 22733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private Account mAccount; 22892551d057965689f1952faeb06763f0762bc717fMindy Pereira private ReplyFromAccount mReplyFromAccount; 229181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 23082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 233326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 234326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private int mComposeMode = -1; 23546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 23646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private String mRecipient; 23746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 238433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private EditText mBodyView; 2391a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 2402eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 241eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 2421883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira @VisibleForTesting 2431883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira protected FromAddressSpinner mFromSpinner; 244013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 245eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 24782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 24882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 24982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 250b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira @VisibleForTesting 251b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira protected Message mRefMessage; 2527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 25444a6339dd80f4b5b9e5d54567021698d92467c5emindyp private ReplyFromAccount mDraftAccount; 2557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 25693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp private View mPhotoAttachmentsButton; 25793b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp private View mVideoAttachmentsButton; 2583ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 259326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 260daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view. 261daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook */ 262daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private boolean mLaunchedFromEmail = false; 263cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mToListener; 264cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mCcListener; 265cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mBccListener; 266b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira private Uri mRefMessageUri; 267a990a715012379451344246c5156d29938f12886Alice Yang private boolean mShowQuotedText = false; 2689f855d667e34fbf0d330845225c26956e540b819Andy Huang private Bundle mInnerSavedState; 269daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 270daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 2711623f9bfde8ced840a52820da28a0939bcaa32f9mindyp // Array of the outstanding send or save tasks. Access is synchronized 2721623f9bfde8ced840a52820da28a0939bcaa32f9mindyp // with the object itself 2731623f9bfde8ced840a52820da28a0939bcaa32f9mindyp /* package for testing */ 2741623f9bfde8ced840a52820da28a0939bcaa32f9mindyp @VisibleForTesting 2751623f9bfde8ced840a52820da28a0939bcaa32f9mindyp public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 2761623f9bfde8ced840a52820da28a0939bcaa32f9mindyp // FIXME: this variable is never read. related to sRequestMessageIdMap. 2771623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private int mRequestId; 2781623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private String mSignature; 2791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private Account[] mAccounts; 2801623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private boolean mRespondedInline; 2811623f9bfde8ced840a52820da28a0939bcaa32f9mindyp 282daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook /** 283326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 284326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 2853ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 2861ebc2db723ed29093d724eb5da906a496ee57224Alice Yang launch(launcher, account, message, EDIT_DRAFT, null, null); 287326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 288326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 29233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 2931ebc2db723ed29093d724eb5da906a496ee57224Alice Yang launch(launcher, account, null, COMPOSE, null, null); 2946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2976349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2986349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2993de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein public static void composeToAddress(Context launcher, Account account, String toAddress) { 3003de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein launch(launcher, account, null, COMPOSE, toAddress, null); 3013de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein } 3023de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein 3033de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein /** 3043de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein * Can be called from a non-UI thread. 3053de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein */ 3060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy public static Intent createReplyIntent(final Context launcher, final Account account, 3070aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Uri messageUri, final boolean isReplyAll) { 3080aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY); 3090aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy } 3100aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3110aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy /** 3120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy * Can be called from a non-UI thread. 3130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy */ 3140aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy public static Intent createForwardIntent(final Context launcher, final Account account, 3150aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Uri messageUri) { 3160aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy return createActionIntent(launcher, account, messageUri, FORWARD); 3170aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy } 3180aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3190aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy private static Intent createActionIntent(final Context launcher, final Account account, 3200aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Uri messageUri, final int action) { 3210aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Intent intent = new Intent(launcher, ComposeActivity.class); 3220aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3236d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook updateActionIntent(account, messageUri, action, intent); 3246d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook 3256d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook return intent; 3266d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook } 3276d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook 3286d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook @VisibleForTesting 3296d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook static Intent updateActionIntent(Account account, Uri messageUri, int action, Intent intent) { 3300aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 3310aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(EXTRA_ACTION, action); 3320aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(Utils.EXTRA_ACCOUNT, account); 3330aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri); 3340aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3350aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy return intent; 3360aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy } 3370aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3380aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy /** 3390aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy * Can be called from a non-UI thread. 3400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy */ 3413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 3421ebc2db723ed29093d724eb5da906a496ee57224Alice Yang launch(launcher, account, message, REPLY, null, null); 3436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 3466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 3476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 3483ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 3491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang launch(launcher, account, message, REPLY_ALL, null, null); 3506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 3536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 3546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 3553ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 3561ebc2db723ed29093d724eb5da906a496ee57224Alice Yang launch(launcher, account, message, FORWARD, null, null); 3576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3591ebc2db723ed29093d724eb5da906a496ee57224Alice Yang public static void reportRenderingFeedback(Context launcher, Account account, Message message, 3601ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String body) { 3611ebc2db723ed29093d724eb5da906a496ee57224Alice Yang launch(launcher, account, message, FORWARD, "android-gmail-readability@google.com", body); 3621ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 3631ebc2db723ed29093d724eb5da906a496ee57224Alice Yang 3641ebc2db723ed29093d724eb5da906a496ee57224Alice Yang private static void launch(Context launcher, Account account, Message message, int action, 3651ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String toAddress, String body) { 3666349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 3676349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 3686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 3696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 370bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 371bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 372bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 373bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 374bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 3751ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (toAddress != null) { 3761ebc2db723ed29093d724eb5da906a496ee57224Alice Yang intent.putExtra(EXTRA_TO, toAddress); 3771ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 3781ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (body != null) { 3791ebc2db723ed29093d724eb5da906a496ee57224Alice Yang intent.putExtra(EXTRA_BODY, body); 3801ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 3816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 3826349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3838e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 3848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 385d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy protected void onCreate(Bundle savedInstanceState) { 3868e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 3878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 3889f855d667e34fbf0d330845225c26956e540b819Andy Huang mInnerSavedState = (savedInstanceState != null) ? 3899f855d667e34fbf0d330845225c26956e540b819Andy Huang savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null; 390b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira checkValidAccounts(); 391b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 392b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 393b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void finishCreate() { 3949f855d667e34fbf0d330845225c26956e540b819Andy Huang final Bundle savedState = mInnerSavedState; 39546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 396818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 397e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message; 39862066e47fe69c33b60ed970e46809ba81d044064Mark Wei ArrayList<AttachmentPreview> previews; 399a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = false; 400e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int action; 40147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // Check for any of the possibly supplied accounts.; 40247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Account account = null; 4039f855d667e34fbf0d330845225c26956e540b819Andy Huang if (hadSavedInstanceStateMessage(savedState)) { 4049f855d667e34fbf0d330845225c26956e540b819Andy Huang action = savedState.getInt(EXTRA_ACTION, COMPOSE); 4059f855d667e34fbf0d330845225c26956e540b819Andy Huang account = savedState.getParcelable(Utils.EXTRA_ACCOUNT); 4069f855d667e34fbf0d330845225c26956e540b819Andy Huang message = (Message) savedState.getParcelable(EXTRA_MESSAGE); 40762066e47fe69c33b60ed970e46809ba81d044064Mark Wei 4089f855d667e34fbf0d330845225c26956e540b819Andy Huang previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS); 4099f855d667e34fbf0d330845225c26956e540b819Andy Huang mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE); 410e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 41147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = obtainAccount(intent); 412e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 413e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // Initialize the message from the message in the intent 414e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 41562066e47fe69c33b60ed970e46809ba81d044064Mark Wei previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS); 416e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 417b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI); 418e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 41962066e47fe69c33b60ed970e46809ba81d044064Mark Wei mAttachmentsView.setAttachmentPreviews(previews); 42092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 42192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 422818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 423818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 424818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 425bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 426fe853d3427119202562519c2add6873590851705Scott Kennedy initRecipients(); 427fe853d3427119202562519c2add6873590851705Scott Kennedy 4285680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy // Clear the notification and mark the conversation as seen, if necessary 4295680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy final Folder notificationFolder = 4305680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER); 4315680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy if (notificationFolder != null) { 4325680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy final Intent clearNotifIntent = 4335680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS); 434d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy clearNotifIntent.setPackage(getPackageName()); 43548cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account); 43648cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder); 4375680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy 4385680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy startService(clearNotifIntent); 4395680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy } 4405680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy 441daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) { 442daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = true; 443daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } else if (Intent.ACTION_SEND.equals(intent.getAction())) { 444daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final Uri dataUri = intent.getData(); 445daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (dataUri != null) { 446daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String dataScheme = intent.getData().getScheme(); 447daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String accountScheme = mAccount.composeIntentUri.getScheme(); 448daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme); 449daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 450daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 451daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 45296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira if (mRefMessageUri != null) { 453a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = true; 454a990a715012379451344246c5156d29938f12886Alice Yang mComposeMode = action; 455a990a715012379451344246c5156d29938f12886Alice Yang getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this); 45696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return; 45796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } else if (message != null && action != EDIT_DRAFT) { 458e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 459e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 4609f855d667e34fbf0d330845225c26956e540b819Andy Huang showCcBcc(savedState); 461a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = message.appendRefMessageContent; 462e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (action == EDIT_DRAFT) { 463e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 4648960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy boolean showBcc = !TextUtils.isEmpty(message.getBcc()); 4658960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc()); 466ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 467bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 468bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 469bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 470bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 471bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 472bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 473bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 474bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 475bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 476bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 477bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 478bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 479bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 480bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 481bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 482bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 483a990a715012379451344246c5156d29938f12886Alice Yang LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action); 484a990a715012379451344246c5156d29938f12886Alice Yang 485a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = message.appendRefMessageContent; 486a990a715012379451344246c5156d29938f12886Alice Yang if (message.refMessageUri != null) { 487a990a715012379451344246c5156d29938f12886Alice Yang // If we're editing an existing draft that was in reference to an existing message, 488a990a715012379451344246c5156d29938f12886Alice Yang // still need to load that original message since we might need to refer to the 489a990a715012379451344246c5156d29938f12886Alice Yang // original sender and recipients if user switches "reply <-> reply-all". 490a990a715012379451344246c5156d29938f12886Alice Yang mRefMessageUri = message.refMessageUri; 491a990a715012379451344246c5156d29938f12886Alice Yang mComposeMode = action; 492a990a715012379451344246c5156d29938f12886Alice Yang getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this); 493a990a715012379451344246c5156d29938f12886Alice Yang return; 494a990a715012379451344246c5156d29938f12886Alice Yang } 495e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 496e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 4970aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy initFromRefMessage(action); 498a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = true; 499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 5008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 5018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromExtras(intent); 502bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 503a990a715012379451344246c5156d29938f12886Alice Yang 504a990a715012379451344246c5156d29938f12886Alice Yang mComposeMode = action; 5059f855d667e34fbf0d330845225c26956e540b819Andy Huang finishSetup(action, intent, savedState); 50696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 507bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 508b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void checkValidAccounts() { 509faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook final Account[] allAccounts = AccountUtils.getAccounts(this); 510faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook if (allAccounts == null || allAccounts.length == 0) { 511b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this); 512b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (noAccountIntent != null) { 513faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook mAccounts = null; 514b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT); 515b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 516b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 51726d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp // If none of the accounts are syncing, setup a watcher. 518b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira boolean anySyncing = false; 519faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook for (Account a : allAccounts) { 520dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook if (a.isAccountReady()) { 521b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira anySyncing = true; 522b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 523b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 524b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 525b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (!anySyncing) { 526b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // There are accounts, but none are sync'd, which is just like having no accounts. 527b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAccounts = null; 528b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); 529b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return; 530b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 531faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook mAccounts = AccountUtils.getSyncingAccounts(this); 532b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishCreate(); 533b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 534b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 535b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 53647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira private Account obtainAccount(Intent intent) { 53747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Account account = null; 53847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Object accountExtra = null; 53947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (intent != null && intent.getExtras() != null) { 54047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT); 54147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (accountExtra instanceof Account) { 54247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira return (Account) accountExtra; 5437ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp } else if (accountExtra instanceof String) { 5447ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp // This is the Account attached to the widget compose intent. 5457ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp account = Account.newinstance((String)accountExtra); 5467ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp if (account != null) { 5477ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp return account; 5487ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp } 54947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 5505ee9dc48884714e9005a1409e7002a0e04bad313mindyp accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ? 5515ee9dc48884714e9005a1409e7002a0e04bad313mindyp intent.getStringExtra(Utils.EXTRA_ACCOUNT) : 5525ee9dc48884714e9005a1409e7002a0e04bad313mindyp intent.getStringExtra(EXTRA_SELECTED_ACCOUNT); 55347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 55447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (account == null) { 5550617446db14891bffaa2748e1fc98526aac1e06dmindyp MailAppProvider provider = MailAppProvider.getInstance(); 5560617446db14891bffaa2748e1fc98526aac1e06dmindyp String lastAccountUri = provider.getLastSentFromAccount(); 5570617446db14891bffaa2748e1fc98526aac1e06dmindyp if (TextUtils.isEmpty(lastAccountUri)) { 5580617446db14891bffaa2748e1fc98526aac1e06dmindyp lastAccountUri = provider.getLastViewedAccount(); 5590617446db14891bffaa2748e1fc98526aac1e06dmindyp } 56047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (!TextUtils.isEmpty(lastAccountUri)) { 56147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = Uri.parse(lastAccountUri); 56247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 56347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 564b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts != null && mAccounts.length > 0) { 56547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) { 56647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // For backwards compatibility, we need to check account 56747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // names. 568b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 56947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (a.name.equals(accountExtra)) { 57047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = a; 57147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 57247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 57347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } else if (accountExtra instanceof Uri) { 57447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // The uri of the last viewed account is what is stored in 57547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // the current code base. 576b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 57747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (a.uri.equals(accountExtra)) { 57847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = a; 57947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 58047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 581b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 582b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (account == null) { 583b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = mAccounts[0]; 58447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 58547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 58647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira return account; 58747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 58847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira 589a990a715012379451344246c5156d29938f12886Alice Yang private void finishSetup(int action, Intent intent, Bundle savedInstanceState) { 59034a3c56570eac4760405b3d5bff5fdc706a22facmindyp setFocus(action); 591bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == COMPOSE) { 592eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mQuotedTextView.setVisibility(View.GONE); 59346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 594f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // Don't bother with the intent if we have procured a message from the 595f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // intent already. 596f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira if (!hadSavedInstanceStateMessage(savedInstanceState)) { 597f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira initAttachmentsFromIntent(intent); 598f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 599a990a715012379451344246c5156d29938f12886Alice Yang initActionBar(); 600e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(), 601e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action); 602d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp 603d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp // If this is a draft message, the draft account is whatever account was 604d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp // used to open the draft message in Compose. 605d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp if (mDraft != null) { 606d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp mDraftAccount = mReplyFromAccount; 607d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp } 608d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp 60975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 610326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira updateHideOrShowCcBcc(); 611a990a715012379451344246c5156d29938f12886Alice Yang updateHideOrShowQuotedText(mShowQuotedText); 6121623f9bfde8ced840a52820da28a0939bcaa32f9mindyp 6139f855d667e34fbf0d330845225c26956e540b819Andy Huang mRespondedInline = mInnerSavedState != null ? 6149f855d667e34fbf0d330845225c26956e540b819Andy Huang mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false; 6151623f9bfde8ced840a52820da28a0939bcaa32f9mindyp if (mRespondedInline) { 6161623f9bfde8ced840a52820da28a0939bcaa32f9mindyp mQuotedTextView.setVisibility(View.GONE); 6171623f9bfde8ced840a52820da28a0939bcaa32f9mindyp } 61871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira } 61971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira 620ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) { 621f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE); 622f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 623f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira 62471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira private void updateHideOrShowQuotedText(boolean showQuotedText) { 62571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira mQuotedTextView.updateCheckedState(showQuotedText); 62640882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 627433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 628433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 629433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private void setFocus(int action) { 630433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (action == EDIT_DRAFT) { 631433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int type = mDraft.draftType; 632433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (type) { 633433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.COMPOSE: 634433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.FORWARD: 635433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = COMPOSE; 636433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 637433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY: 638433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY_ALL: 639433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 640433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = REPLY; 641433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 642433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 643433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 644433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (action) { 645433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case FORWARD: 646433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case COMPOSE: 6472708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp if (TextUtils.isEmpty(mTo.getText())) { 6482708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp mTo.requestFocus(); 6492708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp break; 6502708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp } 651ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy //$FALL-THROUGH$ 652433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY: 653433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY_ALL: 654433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 655433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 656433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 657433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 658433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 659433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 660433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira /** 661433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira * Focus the body of the message. 662433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira */ 663433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira public void focusBody() { 664433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.requestFocus(); 665433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int length = mBodyView.getText().length(); 666433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 667433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int signatureStartPos = getSignatureStartPosition( 668433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mSignature, mBodyView.getText().toString()); 669433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (signatureStartPos > -1) { 670433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // In case the user deleted the newlines... 671433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(signatureStartPos); 6728743cfca851058d50385951b111dd903b1fa6c5amindyp } else if (length >= 0) { 673433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // Move cursor to the end. 674433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(length); 675433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 6761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 6771a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 6781a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 6791a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 6801a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 6811a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 6821a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 683818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 684c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromSpinner.initialize(mComposeMode, mAccount, mAccounts, mRefMessage); 685818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 6861a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 6871a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 688eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 689eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 690eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 691eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 692a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira // When the user exits the compose view, see if this draft needs saving. 6933d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee // Don't save unnecessary drafts if we are only changing the orientation. 6943d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee if (!isChangingConfigurations()) { 695a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira saveIfNeeded(); 696a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira } 697eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 698eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 699eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 700eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 701b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) { 702eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 703b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAddingAttachment = false; 704b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else if (request == RESULT_CREATE_ACCOUNT) { 705a990a715012379451344246c5156d29938f12886Alice Yang // We were waiting for the user to create an account 706b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (result != RESULT_OK) { 707b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 708b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 709b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Watch for accounts to show up! 710b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // restart the loader to get the updated list of accounts 711b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); 712b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira showWaitFragment(null); 713b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 714eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 715eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 716eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 717eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 718d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy protected final void onRestoreInstanceState(Bundle savedInstanceState) { 7197bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee final boolean hasAccounts = mAccounts != null && mAccounts.length > 0; 7207bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee if (hasAccounts) { 7217bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee clearChangeListeners(); 7227bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee } 723e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira super.onRestoreInstanceState(savedInstanceState); 7249f855d667e34fbf0d330845225c26956e540b819Andy Huang if (mInnerSavedState != null) { 7259f855d667e34fbf0d330845225c26956e540b819Andy Huang if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) { 7269f855d667e34fbf0d330845225c26956e540b819Andy Huang int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START); 7279f855d667e34fbf0d330845225c26956e540b819Andy Huang int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END); 728e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // There should be a focus and it should be an EditText since we 729e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // only save these extras if these conditions are true. 730e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) getCurrentFocus(); 731e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira final int length = focusEditText.getText().length(); 732e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectionStart < length && selectionEnd < length) { 733e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira focusEditText.setSelection(selectionStart, selectionEnd); 734e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 735e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 736e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 7377bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee if (hasAccounts) { 7387bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee initChangeListeners(); 7397bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee } 740e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 741e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 742e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira @Override 743d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy protected final void onSaveInstanceState(Bundle state) { 744eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 7459f855d667e34fbf0d330845225c26956e540b819Andy Huang final Bundle inner = new Bundle(); 7469f855d667e34fbf0d330845225c26956e540b819Andy Huang saveState(inner); 7479f855d667e34fbf0d330845225c26956e540b819Andy Huang state.putBundle(KEY_INNER_SAVED_STATE, inner); 7489f855d667e34fbf0d330845225c26956e540b819Andy Huang } 7499f855d667e34fbf0d330845225c26956e540b819Andy Huang 7509f855d667e34fbf0d330845225c26956e540b819Andy Huang private void saveState(Bundle state) { 751b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // We have no accounts so there is nothing to compose, and therefore, nothing to save. 752b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 753b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return; 754b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 755e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // The framework is happy to save and restore the selection but only if it also saves and 756e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // restores the contents of the edit text. That's a lot of text to put in a bundle so we do 757e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // this manually. 758e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira View focus = getCurrentFocus(); 759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (focus != null && focus instanceof EditText) { 760e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) focus; 761e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart()); 762e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd()); 763e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 7646273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook 7656273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 766151f1ad1613ecac0207144472872440517172b5aPaul Westbrook final int selectedPos = mFromSpinner.getSelectedItemPosition(); 767d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null 768d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ? 769d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira replyFromAccounts.get(selectedPos) : null; 770e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectedReplyFromAccount != null) { 771e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize() 772e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .toString()); 773e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account); 774e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 775e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount); 776e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 777eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 778e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) { 779e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We don't have a draft id, and we have a request id, 780e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // save the request id. 781e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_REQUEST_ID, mRequestId); 782e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 783e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 784e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We want to restore the current mode after a pause 785e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // or rotation. 786e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = getMode(); 787e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_ACTION, mode); 788e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 789e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp final Message message = createMessage(selectedReplyFromAccount, mode); 7901f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang if (mDraft != null) { 791e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp message.id = mDraft.id; 792e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp message.serverId = mDraft.serverId; 793e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp message.uri = mDraft.uri; 7941f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang } 795e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_MESSAGE, message); 796e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 797e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 798e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage); 799e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 800326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible()); 801326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible()); 8021623f9bfde8ced840a52820da28a0939bcaa32f9mindyp state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline); 803816b3f0adc04db073820f04ce379e5126e1cbef1mindyp state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled()); 80462066e47fe69c33b60ed970e46809ba81d044064Mark Wei state.putParcelableArrayList( 80562066e47fe69c33b60ed970e46809ba81d044064Mark Wei EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews()); 806e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 807e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 808e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private int getMode() { 809e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = ComposeActivity.COMPOSE; 810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ActionBar actionBar = getActionBar(); 811e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar != null 812e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) { 813e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mode = actionBar.getSelectedNavigationIndex(); 814e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 815e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return mode; 816e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) { 819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = new Message(); 820e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.id = UIProvider.INVALID_MESSAGE_ID; 821d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang message.serverId = null; 822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.uri = null; 823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.conversationUri = null; 824e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.subject = mSubject.getText().toString(); 825e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.snippet = null; 8268960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setTo(formatSenders(mTo.getText().toString())); 8278960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setCc(formatSenders(mCc.getText().toString())); 8288960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setBcc(formatSenders(mBcc.getText().toString())); 8298960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setReplyTo(null); 830e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.dateReceivedMs = 0; 831b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText())); 832b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final StringBuilder fullBody = new StringBuilder(htmlBody); 833e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyHtml = fullBody.toString(); 834e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyText = mBodyView.getText().toString(); 835e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.embedsExternalResources = false; 836a990a715012379451344246c5156d29938f12886Alice Yang message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null; 837e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null; 838e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ArrayList<Attachment> attachments = mAttachmentsView.getAttachments(); 839e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.hasAttachments = attachments != null && attachments.size() > 0; 840e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentListUri = null; 841e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.messageFlags = 0; 842e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.alwaysShowImages = false; 843e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentsJson = Attachment.toJSONArray(attachments); 844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira CharSequence quotedText = mQuotedTextView.getQuotedText(); 845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView 846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .getQuotedTextOffset(quotedText.toString()) : -1; 847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.accountUri = null; 8488960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setFrom(selectedReplyFromAccount != null ? selectedReplyFromAccount.address 8498960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy : mAccount != null ? mAccount.name : null); 8501f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang message.draftType = getDraftType(mode); 851e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp return message; 8521f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang } 8531f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang 854ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static String formatSenders(final String string) { 8553c9115813343861a44133b805fb9f55512d20948Mindy Pereira if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') { 8563c9115813343861a44133b805fb9f55512d20948Mindy Pereira return string.substring(0, string.length() - 1); 8573c9115813343861a44133b805fb9f55512d20948Mindy Pereira } 8583c9115813343861a44133b805fb9f55512d20948Mindy Pereira return string; 8593c9115813343861a44133b805fb9f55512d20948Mindy Pereira } 8603c9115813343861a44133b805fb9f55512d20948Mindy Pereira 861818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 862818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 863bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira if (account == null) { 864bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira return; 865bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira } 86623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 86723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 868b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook mCachedSettings = mAccount.settings; 869b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook appendSignature(); 87023e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 871fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira if (mAccount != null) { 872f6c00b8304062a17d14b484bd1fc33a83c4a90d7Vikram Aggarwal MailActivity.setNfcMessage(mAccount.name); 873fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira } 874818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 875818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 876e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromSpinner(Bundle bundle, int action) { 877e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) { 87862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira action = COMPOSE; 87962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 880c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromSpinner.initialize(action, mAccount, mAccounts, mRefMessage); 881c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook 8829a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle != null) { 8839a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) { 8849a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = ReplyFromAccount.deserialize(mAccount, 8859a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)); 8869a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) { 887c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook final String accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING); 8889a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString); 8899a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } 890e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 891e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mReplyFromAccount == null) { 892e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraft != null) { 893e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft); 894e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (mRefMessage != null) { 895e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage); 896e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 89762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 89862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mReplyFromAccount == null) { 899238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang mReplyFromAccount = getDefaultReplyFromAccount(mAccount); 90062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 9019a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 90262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.setCurrentAccount(mReplyFromAccount); 9039a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 90462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mFromSpinner.getCount() > 1) { 905a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // If there is only 1 account, just show that account. 906a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // Otherwise, give the user the ability to choose which account to 90762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // send mail from / save drafts to. 90862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromStatic.setVisibility(View.GONE); 909c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromStaticText.setText(mReplyFromAccount.name); 91062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinnerWrapper.setVisibility(View.VISIBLE); 911a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } else { 912a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStatic.setVisibility(View.VISIBLE); 913c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromStaticText.setText(mReplyFromAccount.name); 914a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromSpinnerWrapper.setVisibility(View.GONE); 915a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } 91646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 91746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 91862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) { 91962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (refMessage.accountUri != null) { 92062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // This must be from combined inbox. 92162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 92262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 92362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.account.uri.equals(refMessage.accountUri)) { 92462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 92562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 92662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 92762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return null; 92862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 92962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getReplyFromAccount(account, refMessage); 93062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 93162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 93262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 93362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 9349016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler * Given an account and the message we're replying to, 93562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * return who the message should be sent from. 93662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param account Account in which the message arrived. 9379016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler * @param refMessage Message to analyze for account selection 93862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @return the address from which to reply. 93962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 94062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) { 94162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // First see if we are supposed to use the default address or 94262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // the address it was sentTo. 943326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (mCachedSettings.forceReplyFromDefault) { 94462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getDefaultReplyFromAccount(account); 94562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 94689bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira // If we aren't explicitly told which account to look for, look at 94762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // all the message recipients and find one that matches 94862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // a custom from or account. 94962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<String> allRecipients = new ArrayList<String>(); 9509016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler allRecipients.addAll(Arrays.asList(refMessage.getToAddressesUnescaped())); 9519016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler allRecipients.addAll(Arrays.asList(refMessage.getCcAddressesUnescaped())); 95262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getMatchingRecipient(account, allRecipients); 95362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 95462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 95562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 95662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 95762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Compare all the recipients of an email to the current account and all 95862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * custom addresses associated with that account. Return the match if there 95962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * is one, or the default account if there isn't. 96062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 96162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) { 96262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // Tokenize the list and place in a hashmap. 96362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount matchingReplyFrom = null; 96462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira Rfc822Token[] tokens; 96562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira HashSet<String> recipientsMap = new HashSet<String>(); 96662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (String address : sentTo) { 96762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira tokens = Rfc822Tokenizer.tokenize(address); 96862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (int i = 0; i < tokens.length; i++) { 96962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira recipientsMap.add(tokens[i].getAddress()); 97062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 97162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 97262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 97362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira int matchingAddressCount = 0; 97462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> customFroms; 9751617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang customFroms = account.getReplyFroms(); 9761617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang if (customFroms != null) { 9771617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang for (ReplyFromAccount entry : customFroms) { 9781617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang if (recipientsMap.contains(entry.address)) { 9791617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang matchingReplyFrom = entry; 9801617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang matchingAddressCount++; 98162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 98262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 98362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 98462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (matchingAddressCount > 1) { 98562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = getDefaultReplyFromAccount(account); 98662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 98762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return matchingReplyFrom; 98862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 98962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 990ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) { 991ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final ReplyFromAccount from : account.getReplyFroms()) { 99262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.isDefault) { 99362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 996cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name, 997cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira true, false); 99862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 99962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 1000e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) { 10018960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy String sender = msg.getFrom(); 100262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount replyFromAccount = null; 100362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 100462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(account.name, sender)) { 100562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 1006cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira mAccount.name, mAccount.name, true, false); 100762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 100862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount fromAccount : replyFromAccounts) { 100962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(fromAccount.name, sender)) { 101062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = fromAccount; 101162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira break; 101262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 101362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 101462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 101562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return replyFromAccount; 101662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 101762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 101846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 1019b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.compose).setVisibility(View.VISIBLE); 1020a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 10218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 10228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 10238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 10248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 10257b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 102693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment); 1027cd0b0b950efebfc3964334067747b97e61c4f027mindyp if (mPhotoAttachmentsButton != null) { 1028cd0b0b950efebfc3964334067747b97e61c4f027mindyp mPhotoAttachmentsButton.setOnClickListener(this); 1029cd0b0b950efebfc3964334067747b97e61c4f027mindyp } 103093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp mVideoAttachmentsButton = findViewById(R.id.add_video_attachment); 1031cd0b0b950efebfc3964334067747b97e61c4f027mindyp if (mVideoAttachmentsButton != null) { 1032cd0b0b950efebfc3964334067747b97e61c4f027mindyp mVideoAttachmentsButton.setOnClickListener(this); 1033cd0b0b950efebfc3964334067747b97e61c4f027mindyp } 1034818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 103541500399a7ee9066319c0b07055638b07312c8acScott Kennedy mTo.setTokenizer(new Rfc822Tokenizer()); 1036818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 103741500399a7ee9066319c0b07055638b07312c8acScott Kennedy mCc.setTokenizer(new Rfc822Tokenizer()); 1038818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 103941500399a7ee9066319c0b07055638b07312c8acScott Kennedy mBcc.setTokenizer(new Rfc822Tokenizer()); 104082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 104182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 10426349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 104362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp mSubject.setOnEditorActionListener(this); 104446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 104546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 1046433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView = (EditText) findViewById(R.id.body); 10471a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 10482eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 1049eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 10505a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 1051326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1052326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 105362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp @Override 105462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) { 105562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp if (action == EditorInfo.IME_ACTION_DONE) { 105662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp focusBody(); 105762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp return true; 105862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp } 105962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp return false; 106062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp } 106162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp 1062e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira protected TextView getBody() { 1063e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mBodyView; 1064e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 1065e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 1066e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1067e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public Account getFromAccount() { 1068e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mReplyFromAccount != null && mReplyFromAccount.account != null ? 1069e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira mReplyFromAccount.account : mAccount; 1070e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 1071e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 1072cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private void clearChangeListeners() { 1073cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mSubject.removeTextChangedListener(this); 1074cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBodyView.removeTextChangedListener(this); 1075cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mTo.removeTextChangedListener(mToListener); 1076cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCc.removeTextChangedListener(mCcListener); 1077cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBcc.removeTextChangedListener(mBccListener); 1078cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mFromSpinner.setOnAccountChangedListener(null); 1079cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mAttachmentsView.setAttachmentChangesListener(null); 1080cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1081cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira 108275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 108375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 108475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 108575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 10861d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp // Make sure we only add text changed listeners once! 10871d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp clearChangeListeners(); 108875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 108975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 1090cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mToListener == null) { 1091cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mToListener = new RecipientTextWatcher(mTo, this); 1092cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1093cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mTo.addTextChangedListener(mToListener); 1094cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mCcListener == null) { 1095cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCcListener = new RecipientTextWatcher(mCc, this); 1096cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1097cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCc.addTextChangedListener(mCcListener); 1098cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mBccListener == null) { 1099cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBccListener = new RecipientTextWatcher(mBcc, this); 1100cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1101cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBcc.addTextChangedListener(mBccListener); 110275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 1103818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 110475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 110575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 1106a990a715012379451344246c5156d29938f12886Alice Yang private void initActionBar() { 1107a990a715012379451344246c5156d29938f12886Alice Yang LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity"); 1108eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 1109e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar == null) { 1110e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return; 1111e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 1112a990a715012379451344246c5156d29938f12886Alice Yang if (mComposeMode == ComposeActivity.COMPOSE) { 1113eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 1114eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 1115326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 1116eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 1117326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 1118326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 1119326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1120eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 1121eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 1122a990a715012379451344246c5156d29938f12886Alice Yang switch (mComposeMode) { 1123326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 1124eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 1125326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 1126326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 1127eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 1128326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 1129326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 1130eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 1131326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 1132326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 11336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 1134fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 1135fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 1136fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 11376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 11386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 11390aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy private void initFromRefMessage(int action) { 11400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy setFieldsFromRefMessage(action); 11411ebc2db723ed29093d724eb5da906a496ee57224Alice Yang 11421ebc2db723ed29093d724eb5da906a496ee57224Alice Yang // Check if To: address and email body needs to be prefilled based on extras. 11431ebc2db723ed29093d724eb5da906a496ee57224Alice Yang // This is used for reporting rendering feedback. 11441ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) { 11451ebc2db723ed29093d724eb5da906a496ee57224Alice Yang Intent intent = getIntent(); 11461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (intent.getExtras() != null) { 11471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String toAddresses = intent.getStringExtra(EXTRA_TO); 11481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (toAddresses != null) { 11491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ","))); 11501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 11511ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String body = intent.getStringExtra(EXTRA_BODY); 11521ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (body != null) { 11531ebc2db723ed29093d724eb5da906a496ee57224Alice Yang setBody(body, false /* withSignature */); 11541ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 11551ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 11561ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 11571ebc2db723ed29093d724eb5da906a496ee57224Alice Yang 115896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira if (mRefMessage != null) { 115996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // CC field only gets populated when doing REPLY_ALL. 116096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // BCC never gets auto-populated, unless the user is editing 116196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // a draft with one. 116229a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) { 116396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira mCcBccView.show(false, true, false); 116496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 116596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 116696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira updateHideOrShowCcBcc(); 116796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 116896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 11690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy private void setFieldsFromRefMessage(int action) { 11708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 11718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 11728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 11748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11750aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy initRecipientsFromRefMessage(mRefMessage, action); 1176e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 11778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 11788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 11796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 1180c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 1181c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 1182e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromDraftMessage(Message message) { 11831f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message); 1184bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 1185bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 1186bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 1187bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 1188bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 11899016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler final List<String> toAddresses = Arrays.asList(message.getToAddressesUnescaped()); 1190bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 11919016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler addCcAddresses(Arrays.asList(message.getCcAddressesUnescaped()), toAddresses); 11929016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler addBccAddresses(Arrays.asList(message.getBccAddressesUnescaped())); 11932421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (message.hasAttachments) { 11942421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira List<Attachment> attachments = message.getAttachments(); 11952421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira for (Attachment a : attachments) { 11965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(a); 11972421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 11982421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1199cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira int quotedTextIndex = message.appendRefMessageContent ? 1200002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.quotedTextOffset : -1; 1201bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 1202002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence quotedText = null; 1203bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 1204752222d839d9afeb5c4665669eab81645e413495Mindy Pereira CharSequence htmlText = ""; 1205002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 1206752222d839d9afeb5c4665669eab81645e413495Mindy Pereira // Find the offset in the htmltext of the actual quoted text and strip it out. 1207752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml); 1208752222d839d9afeb5c4665669eab81645e413495Mindy Pereira if (quotedTextIndex > -1) { 1209c59dd8270215f97d39697dae9e69976bcfe3642bmindyp htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0, 1210c59dd8270215f97d39697dae9e69976bcfe3642bmindyp quotedTextIndex)); 1211752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedText = message.bodyHtml.subSequence(quotedTextIndex, 1212752222d839d9afeb5c4665669eab81645e413495Mindy Pereira message.bodyHtml.length()); 1213752222d839d9afeb5c4665669eab81645e413495Mindy Pereira } 12141a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira } else { 1215c59dd8270215f97d39697dae9e69976bcfe3642bmindyp htmlText = Utils.convertHtmlToPlainText(message.bodyHtml); 1216002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1217002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(htmlText); 1218bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 1219752222d839d9afeb5c4665669eab81645e413495Mindy Pereira final String body = message.bodyText; 1220752222d839d9afeb5c4665669eab81645e413495Mindy Pereira final CharSequence bodyText = !TextUtils.isEmpty(body) ? 1221752222d839d9afeb5c4665669eab81645e413495Mindy Pereira (quotedTextIndex > -1 ? 1222752222d839d9afeb5c4665669eab81645e413495Mindy Pereira message.bodyText.substring(0, quotedTextIndex) : message.bodyText) 1223752222d839d9afeb5c4665669eab81645e413495Mindy Pereira : ""; 1224002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 1225752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex) 1226752222d839d9afeb5c4665669eab81645e413495Mindy Pereira : null; 1227002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1228002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(bodyText); 1229002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1230002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1 && quotedText != null) { 12313971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward); 1232bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1233bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1234bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 12358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 12368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 12378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 12388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 12398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 12408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 12418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 12428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 12438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 12448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 12458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromExtras(Intent intent) { 12468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 12478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 12488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 12498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 12508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 12518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 12528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 12530b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira if (!mAccount.composeIntentUri.equals(dataUri)) { 12548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 12558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 12568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 1257dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(toText, ","))); 12588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 12688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 12698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 12828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 12838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 12848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 1285dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(value, ","))); 12868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 1287dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null); 12888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 1289dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addBccAddresses(Arrays.asList(TextUtils.split(value, ","))); 12908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 12918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 12928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 12938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 12948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 12998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 13008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 13018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 13028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 13038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1305e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 1306e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 13078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 13088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 1309a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // TODO: handle the case where there are spaces in the display name as 1310a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>" 1311a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // as they could be encoded ambiguously. 13128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 13138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 13148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 1315a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira try { 13167dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME); 1317a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } catch (IllegalArgumentException e) { 1318a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 1319a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s); 1320a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } else { 1321a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 1322a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 1323a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira return null; 1324a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 13258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 13287dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from 13297dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * changing '+' into ' ' 13307dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * 13317dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * @param toReplace Input string 13327dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * @return The string with all "+" characters replaced with "%2B" 13337dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee */ 13343b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy private static String replacePlus(String toReplace) { 13357dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee return toReplace.replace("+", "%2B"); 13367dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee } 13377dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee 13387dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee /** 13398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 13408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 13418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 13448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 13468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 13508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 13518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 13528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 13538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 13548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1356a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (!TextUtils.isEmpty(to)) { 1357a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira addToAddresses(Arrays.asList(TextUtils.split(to, ","))); 1358a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 13598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 13608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 13778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 13788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 13797dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)), 13807dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee UTF8_ENCODING_NAME)); 13818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 13828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 13838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 13888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 13907dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME), 13918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 13928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 13938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 13948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1398bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira @VisibleForTesting 1399bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira protected void initAttachments(Message refMessage) { 1400434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei addAttachments(refMessage.getAttachments()); 1401434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1402434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei 1403434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei public long addAttachments(List<Attachment> attachments) { 1404434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei long size = 0; 1405434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei AttachmentFailureException error = null; 1406434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei for (Attachment a : attachments) { 1407434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei try { 1408434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei size += mAttachmentsView.addAttachment(mAccount, a); 1409434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } catch (AttachmentFailureException e) { 1410434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei error = e; 1411434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1412434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1413434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei if (error != null) { 1414434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei LogUtils.e(LOG_TAG, error, "Error adding attachment"); 1415434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei if (attachments.size() > 1) { 1416434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(R.string.too_large_to_attach_multiple); 1417434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } else { 1418434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(error.getErrorRes()); 1419434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 14203cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 1421434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei return size; 14223cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 14233cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira 14243cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira /** 14253cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * When an attachment is too large to be added to a message, show a toast. 14263cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * This method also updates the position of the toast so that it is shown 14273cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * clearly above they keyboard if it happens to be open. 14283cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira */ 1429434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei private void showAttachmentTooBigToast(int errorRes) { 1430434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei String maxSize = AttachmentUtils.convertToHumanReadableSize( 1431434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), mAccount.settings.getMaxAttachmentSize()); 1432434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getString(errorRes, maxSize)); 14333cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 14343cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira 1435434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei private void showErrorToast(String message) { 1436434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG); 1437434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei t.setText(message); 14383cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira t.setGravity(Gravity.CENTER_HORIZONTAL, 0, 14393cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset)); 14403cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira t.show(); 1441eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1442eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1443f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 144403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook Bundle extras = intent.getExtras(); 144503ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook if (extras == null) { 144603ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook extras = Bundle.EMPTY; 144703ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook } 1448f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 1449f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 1450f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 1451f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 1452f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 1453f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 1454f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 1455f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1456f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 14575c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 1458f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1459f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1460434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1461f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1462f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1463f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1464f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 14659a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp if (extras.containsKey(Intent.EXTRA_STREAM)) { 14669a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp if (Intent.ACTION_SEND_MULTIPLE.equals(action)) { 14679a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp ArrayList<Parcelable> uris = extras 14689a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp .getParcelableArrayList(Intent.EXTRA_STREAM); 14699a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp ArrayList<Attachment> attachments = new ArrayList<Attachment>(); 14709a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp for (Parcelable uri : uris) { 14719a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp try { 14729a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp attachments.add(mAttachmentsView.generateLocalAttachment((Uri) uri)); 14739a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } catch (AttachmentFailureException e) { 14749a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp LogUtils.e(LOG_TAG, e, "Error adding attachment"); 14759a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp String maxSize = AttachmentUtils.convertToHumanReadableSize( 14769a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp getApplicationContext(), 14779a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp mAccount.settings.getMaxAttachmentSize()); 14789a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp showErrorToast(getString 14799a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp (R.string.generic_attachment_problem, maxSize)); 14809a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } 14819a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } 14829a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp totalSize += addAttachments(attachments); 14839a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } else { 14849a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 14859a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp long size = 0; 1486f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 14879a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp size = mAttachmentsView.addAttachment(mAccount, uri); 1488f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1489f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 14909a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp showAttachmentTooBigToast(e.getErrorRes()); 1491f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 14929a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp totalSize += size; 1493f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1494f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1495f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1496f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 1497f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 1498f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 1499f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1500f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1501f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1502f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1503f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1504e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initQuotedTextFromRefMessage(Message refMessage, int action) { 1505e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) { 15069932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 15079932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 150846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 150946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 151046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 1511ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1512326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean ccVisible = mCcBccView.isCcVisible(); 1513326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean bccVisible = mCcBccView.isBccVisible(); 1514ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1515326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (!ccVisible || !bccVisible) { 1516ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 1517326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label 1518ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1519ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1520cd0b0b950efebfc3964334067747b97e61c4f027mindyp mCcBccButton.setVisibility(View.INVISIBLE); 1521ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1522ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 152346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 152446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1525a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira private void showCcBcc(Bundle state) { 1526326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (state != null && state.containsKey(EXTRA_SHOW_CC)) { 1527326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showCc = state.getBoolean(EXTRA_SHOW_CC); 1528326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC); 1529326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (showCc || showBcc) { 1530326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccView.show(false, showCc, showBcc); 1531326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1532326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1533326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1534326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira 1535013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 1536013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 1537013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 1538013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 1539013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 15402421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null); 15412421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 15422421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira 15435c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Uri contentUri) { 15445c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang if (contentUri == null) { 15452421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira return; 15462421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1547013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 15485c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri)); 15495c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } catch (AttachmentFailureException e) { 15505c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1551434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getResources().getString( 1552434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei e.getErrorRes(), 1553434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei AttachmentUtils.convertToHumanReadableSize( 1554434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), mAccount.settings.getMaxAttachmentSize()))); 15555c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 15565c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 15575c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang 15585c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Attachment attachment) { 15595c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang try { 1560434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei long size = mAttachmentsView.addAttachment(mAccount, attachment); 15619932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 15629932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 15639932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 1564013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 15659932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 15669932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1567434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1568013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1569013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1570013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 15710aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy void initRecipientsFromRefMessage(Message refMessage, int action) { 15724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 15734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 15744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 15754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 1576ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy initReplyRecipients(refMessage, action); 15774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 15784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15796d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook // TODO: This should be private. This method shouldn't be used by ComposeActivityTests, as 15806d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook // it doesn't setup the state of the activity correctly 1581818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 1582ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy void initReplyRecipients(final Message refMessage, final int action) { 15839016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler String[] sentToAddresses = refMessage.getToAddressesUnescaped(); 1584a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 158589de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler final String[] replyToAddresses = refMessage.getReplyToAddressesUnescaped(); 158689de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler String replyToAddress = replyToAddresses.length > 0 ? replyToAddresses[0] : null; 158789de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler final String[] fromAddresses = refMessage.getFromAddressesUnescaped(); 158889de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler final String fromAddress = fromAddresses.length > 0 ? fromAddresses[0] : null; 158989de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler 159065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // If there is no reply to address, the reply to address is the sender. 159189de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler if (TextUtils.isEmpty(replyToAddress)) { 159289de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler replyToAddress = fromAddress; 159365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp } 15944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 15954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 15964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 15974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 1598a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 1599a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 160089de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses); 1601a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 1602a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 16034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 160489de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses); 1605154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 1606ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy addRecipients(ccAddresses, sentToAddresses); 16079016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler addRecipients(ccAddresses, refMessage.getCcAddressesUnescaped()); 16084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 16094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 16134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 16144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 16178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 16188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 16194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1621bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 1622bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 1623bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1624bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 16254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 16264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 16274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 16284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 16294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 16318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 16328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 16338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 16344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 16354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 16388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 16398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 16408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 16418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 16428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 16438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 16448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 16458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 16468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 16478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 16488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 16494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1652ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) { 1653ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final HashSet<String> hash = new HashSet<String>(); 1654ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final Rfc822Token[] tokens : list) { 16554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 16564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 16574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 16604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 16634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 16644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 16654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 16674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 16684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 16704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 16734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 16744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 16754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 16764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1679ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static void addAddressToList(final String address, final RecipientEditTextView list) { 16804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 16814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 16824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1683ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 16844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 16864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 16874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 16894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 16904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 1691ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy protected Collection<String> initToRecipients(final String fullSenderAddress, 1692ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final String replyToAddress, final String[] inToAddresses) { 16934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 16944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 16954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 16964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 16974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 16984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 169965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) { 17003ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 17014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 170265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // In this case, the user is replying to a message in which their 170365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // current account or one of their custom from addresses is the only 170465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // recipient and they sent the original message. 170565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress) 170665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp && recipientMatchesThisAccount(inToAddresses[0])) { 170765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp toAddresses.add(inToAddresses[0]); 170865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp return toAddresses; 170965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp } 171065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // This happens if the user replies to a message they originally 171165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // wrote. In this case, "reply" really means "re-send," so we 171265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // target the original recipients. This works as expected even 171365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // if the user sent the original message to themselves. 171465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp for (String address : inToAddresses) { 171565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp if (!recipientMatchesThisAccount(address)) { 171665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp toAddresses.add(address); 1717fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp } 17181469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 17194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 17214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1723ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private void addRecipients(final Set<String> recipients, final String[] addresses) { 1724ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final String email : addresses) { 1725cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira // Do not add this account, or any of its custom from addresses, to 1726cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira // the list of recipients. 17274a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 17285ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp if (!recipientMatchesThisAccount(recipientAddress)) { 17294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 17304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 173246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 173346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1734cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira /** 1735cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * A recipient matches this account if it has the same address as the 1736cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * currently selected account OR one of the custom from addresses associated 1737cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * with the currently selected account. 1738cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @param recipientAddress address we are comparing with the currently selected account 1739cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @return 1740cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira */ 17415ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp protected boolean recipientMatchesThisAccount(String recipientAddress) { 17425ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress, 1743fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp mAccount.getReplyFroms()); 1744cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira } 1745cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira 17463ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void setSubject(Message refMessage, int action) { 17473ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String subject = refMessage.subject; 174846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 174946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 175046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 175146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 175246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 175346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.forward_subject_label); 175446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 175546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.reply_subject_label); 175646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 175746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 175846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 1759c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira if (!TextUtils.isEmpty(subject) 1760c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira && subject.toLowerCase().startsWith(prefix.toLowerCase())) { 176146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 176246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 176346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = String 176446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira .format(getString(R.string.formatted_subject), prefix, subject); 176546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 176646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mSubject.setText(correctedSubject); 176746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 176846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1769818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 1770818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 1771818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 1772818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 1773eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1774eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1775818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 1776679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 177782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 1778679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook final String accountName = mAccount.name; 177933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 178033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 1781c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira if (offset > -1) { 178233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira account = account.substring(accountName.indexOf("@") + 1); 1783c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 178482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 1785c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 178682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 17878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 17888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 17898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 17908e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 17912b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final int id = v.getId(); 17922b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (id == R.id.add_cc_bcc) { 17932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Verify that cc/ bcc aren't showing. 17942b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Animate in cc/bcc. 17952b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy showCcBccViews(); 17962b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_photo_attachment) { 17972b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_PHOTO); 17982b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_video_attachment) { 17992b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_VIDEO); 18008e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 18018e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1802b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1803b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1804b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 1805b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira super.onCreateOptionsMenu(menu); 1806b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Don't render any menu items when there are no accounts. 1807b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 1808b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return true; 1809b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1810b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1811b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 18121d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp 18131d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp /* 18141d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * Start save in the correct enabled state. 18151d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * 1) If a user launches compose from within gmail, save is disabled 18161d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * until they add something, at which point, save is enabled, auto save 18171d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * on exit; if the user empties everything, save is disabled, exiting does not 18181d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * auto-save 18191d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * 2) if a user replies/ reply all/ forwards from within gmail, save is 18201d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * disabled until they change something, at which point, save is 18211d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * enabled, auto save on exit; if the user empties everything, save is 18221d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * disabled, exiting does not auto-save. 18231d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * 3) If a user launches compose from another application and something 18241d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * gets populated (attachments, recipients, body, subject, etc), save is 18251d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * enabled, auto save on exit; if the user empties everything, save is 18261d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * disabled, exiting does not auto-save 18271d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp */ 182882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 18291d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp String action = getIntent() != null ? getIntent().getAction() : null; 18309f855d667e34fbf0d330845225c26956e540b819Andy Huang enableSave(mInnerSavedState != null ? 18319f855d667e34fbf0d330845225c26956e540b819Andy Huang mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED) 18321d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp : (Intent.ACTION_SEND.equals(action) 18331d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp || Intent.ACTION_SEND_MULTIPLE.equals(action) 18341d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp || Intent.ACTION_SENDTO.equals(action) 18351d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp || shouldSave())); 18361d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp 183782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 18383ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem helpItem = menu.findItem(R.id.help_info_menu_item); 18393ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item); 18403ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (helpItem != null) { 18413ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira helpItem.setVisible(mAccount != null 18423ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT)); 18433ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 18443ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (sendFeedbackItem != null) { 18453ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira sendFeedbackItem.setVisible(mAccount != null 18463ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK)); 18473ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 1848b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1849b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1850b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1851b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1852ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 1853ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 1854818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 1855ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1856ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 1857ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 1858ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 1859ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 1860ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 1861ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1862ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1863ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 1864ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1865ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1866ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 1867ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1868ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1869ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 1870b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 18712b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final int id = item.getItemId(); 187275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 18732b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (id == R.id.add_photo_attachment) { 18742b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_PHOTO); 18752b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_video_attachment) { 18762b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_VIDEO); 18772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_cc_bcc) { 18782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy showCcBccViews(); 18792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.save) { 18802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doSave(true); 18812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.send) { 18822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doSend(); 18832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.discard) { 18842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doDiscard(); 18852b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.settings) { 18862b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.showSettings(this, mAccount); 18872b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == android.R.id.home) { 18882b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy onAppUpPressed(); 18892b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.help_info_menu_item) { 18902b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.showHelp(this, mAccount, getString(R.string.compose_help_context)); 18912b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.feedback_menu_item) { 18922b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.sendFeedback(this, mAccount, false); 18932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else { 18942b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy handled = false; 1895b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1896b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 1897b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1898326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1899b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira @Override 1900b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira public void onBackPressed() { 1901b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // If we are showing the wait fragment, just exit. 1902b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (getWaitFragment() != null) { 1903b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 1904b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 1905b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira super.onBackPressed(); 1906b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1907b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1908b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 19091672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal /** 19101672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal * Carries out the "up" action in the action bar. 19111672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal */ 1912daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private void onAppUpPressed() { 1913daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (mLaunchedFromEmail) { 1914daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // If this was started from Gmail, simply treat app up as the system back button, so 1915daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // that the last view is restored. 1916daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook onBackPressed(); 1917daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook return; 1918daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 1919daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 1920daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Fire the main activity to ensure it launches the "top" screen of mail. 1921daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Since the main Activity is singleTask, it should revive that task if it was already 1922daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // started. 19230c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal final Intent mailIntent = Utils.createViewInboxIntent(mAccount); 1924daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 1925daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook Intent.FLAG_ACTIVITY_TASK_ON_HOME); 1926daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook startActivity(mailIntent); 1927daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook finish(); 1928daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 1929daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 193033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 1931dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei sendOrSaveWithSanityChecks(false, true, false, false); 193233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 193333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 193448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira private void doSave(boolean showToast) { 1935dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei sendOrSaveWithSanityChecks(true, showToast, false, false); 193648e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira } 193748e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira 1938e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1939e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public interface SendOrSaveCallback { 194082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 19417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 19427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 194382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 194482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 194582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1946e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1947e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveTask implements Runnable { 194882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 194982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 1950e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveCallback mSendOrSaveCallback; 1951e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1952e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveMessage mSendOrSaveMessage; 195344a6339dd80f4b5b9e5d54567021698d92467c5emindyp private ReplyFromAccount mExistingDraftAccount; 195482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 195582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 195644a6339dd80f4b5b9e5d54567021698d92467c5emindyp SendOrSaveCallback callback, ReplyFromAccount draftAccount) { 195782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 195882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 195982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 196044a6339dd80f4b5b9e5d54567021698d92467c5emindyp mExistingDraftAccount = draftAccount; 196182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 196282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 196382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 196482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 19657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 196682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 196792551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount; 19687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 19697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 197082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 197182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 197282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 197344a6339dd80f4b5b9e5d54567021698d92467c5emindyp if (mExistingDraftAccount != null 197444a6339dd80f4b5b9e5d54567021698d92467c5emindyp && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) { 197582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 197682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 197782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 197882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 1979febd226e871263aeb21d436bee81eb2f7dec3d03mindyp if (mExistingDraftAccount.account.expungeMessageUri != null) { 1980febd226e871263aeb21d436bee81eb2f7dec3d03mindyp new ContentProviderTask.UpdateTask() 1981febd226e871263aeb21d436bee81eb2f7dec3d03mindyp .run(resolver, mExistingDraftAccount.account.expungeMessageUri, 1982febd226e871263aeb21d436bee81eb2f7dec3d03mindyp values, null, null); 1983cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1984cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 1985eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 198682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 198782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 198882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 198982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 199082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 199182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 1992ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount); 199372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 199472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook if (!sendOrSaveMessage.mSave) { 199572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.incrementRecipientsTimesContacted(mContext, 199672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 199772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.incrementRecipientsTimesContacted(mContext, 199872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 199972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.incrementRecipientsTimesContacted(mContext, 200072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 200172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 200272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 200372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 200472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 200572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook /** 200672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * Send or Save a message. 200772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook */ 2008ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private void sendOrSaveMessage(final long messageIdToSave, 2009ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) { 201072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final ContentResolver resolver = mContext.getContentResolver(); 201172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID; 201272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 201372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final String accountMethod = sendOrSaveMessage.mSave ? 201472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.AccountCallMethods.SAVE_MESSAGE : 201572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.AccountCallMethods.SEND_MESSAGE; 201672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 20173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook try { 20183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (updateExistingMessage) { 20193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 20203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 2021013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook callAccountSendSaveMethod(resolver, 20223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook selectedAccount.account, accountMethod, sendOrSaveMessage); 202372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else { 2024013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook Uri messageUri = null; 20253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle result = callAccountSendSaveMethod(resolver, 20263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook selectedAccount.account, accountMethod, sendOrSaveMessage); 20273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (result != null) { 20283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // If a non-null value was returned, then the provider handled the call 20293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // method 20303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook messageUri = result.getParcelable(UIProvider.MessageColumns.URI); 20313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 20323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (sendOrSaveMessage.mSave && messageUri != null) { 20333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Cursor messageCursor = resolver.query(messageUri, 20343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook UIProvider.MESSAGE_PROJECTION, null, null, null); 20353c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (messageCursor != null) { 20363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook try { 20373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (messageCursor.moveToFirst()) { 20383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // Broadcast notification that a new message has 20393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // been allocated 20403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 20413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook new Message(messageCursor)); 20423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 20433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } finally { 20443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook messageCursor.close(); 20453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 20463c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 20473c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 204872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 20493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } finally { 20503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // Close any opened file descriptors 20513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook closeOpenedAttachmentFds(sendOrSaveMessage); 20523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 20533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 20543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 2055ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) { 20563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle openedFds = sendOrSaveMessage.attachmentFds(); 20573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (openedFds != null) { 20583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Set<String> keys = openedFds.keySet(); 2059ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final String key : keys) { 20603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final ParcelFileDescriptor fd = openedFds.getParcelable(key); 20613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (fd != null) { 2062ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 20633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook fd.close(); 20643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } catch (IOException e) { 20653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // Do nothing 2066ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 20677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 20687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 206982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 207072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 207182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 207272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook /** 207372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * Use the {@link ContentResolver#call()} method to send or save the message. 207472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * 207572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * If this was successful, this method will return an non-null Bundle instance 207672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook */ 2077ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static Bundle callAccountSendSaveMethod(final ContentResolver resolver, 2078ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final Account account, final String method, 2079ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final SendOrSaveMessage sendOrSaveMessage) { 208072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook // Copy all of the values from the content values to the bundle 208172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size()); 208272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet(); 208372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 208472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook for (Entry<String, Object> entry : valueSet) { 208572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final Object entryValue = entry.getValue(); 208672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final String key = entry.getKey(); 208772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook if (entryValue instanceof String) { 208872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putString(key, (String)entryValue); 208972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else if (entryValue instanceof Boolean) { 209072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putBoolean(key, (Boolean)entryValue); 209172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else if (entryValue instanceof Integer) { 209272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putInt(key, (Integer)entryValue); 209372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else if (entryValue instanceof Long) { 209472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putLong(key, (Long)entryValue); 209572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else { 209672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook LogUtils.wtf(LOG_TAG, "Unexpected object type: %s", 209772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook entryValue.getClass().getName()); 209872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 209982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 210072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 21013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // If the SendOrSaveMessage has some opened fds, add them to the bundle 21023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle fdMap = sendOrSaveMessage.attachmentFds(); 21033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (fdMap != null) { 21043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook methodExtras.putParcelable( 21053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap); 21063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 210872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook return resolver.call(account.uri, method, account.uri.toString(), methodExtras); 210982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 211082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 211182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2112e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2113e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveMessage { 211492551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount mAccount; 211582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 21163ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 2117e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2118e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final boolean mSave; 211982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 21203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook private final Bundle mAttachmentFds; 212182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 21223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values, 21233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook String refMessageId, List<Attachment> attachments, boolean save) { 212482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 212682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 212782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 212882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 21293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook mAttachmentFds = initializeAttachmentFds(context, attachments); 213182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 213382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 213482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 213582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 21363c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21373c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook Bundle attachmentFds() { 21383c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook return mAttachmentFds; 21393c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21403c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21413c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook /** 21423c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook * Opens {@link ParcelFileDescriptor} for each of the attachments. This method must be 21433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook * called before the ComposeActivity finishes. 21443c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook * Note: The caller is responsible for closing these file descriptors. 21453c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook */ 2146ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static Bundle initializeAttachmentFds(final Context context, 2147ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final List<Attachment> attachments) { 21483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (attachments == null || attachments.size() == 0) { 21493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook return null; 21503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle result = new Bundle(attachments.size()); 21533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final ContentResolver resolver = context.getContentResolver(); 21543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook for (Attachment attachment : attachments) { 21563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (attachment == null || Utils.isEmpty(attachment.contentUri)) { 21573c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook continue; 21583c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21593c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21603c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook ParcelFileDescriptor fileDescriptor; 21613c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook try { 21623c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r"); 21633c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } catch (FileNotFoundException e) { 21643c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment"); 21653c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook fileDescriptor = null; 2166c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook } catch (SecurityException e) { 2167c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // We have encountered a security exception when attempting to open the file 2168c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // specified by the content uri. If the attachment has been cached, this 2169c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // isn't a problem, as even through the original permission may have been 2170c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // revoked, we have cached the file. This will happen when saving/sending 2171c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // a previously saved draft. 2172c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // TODO(markwei): Expose whether the attachment has been cached through the 2173c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // attachment object. This would allow us to limit when the log is made, as 2174c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // if the attachment has been cached, this really isn't an error 2175c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment"); 2176c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // Just set the file descriptor to null, as the underlying provider needs 2177c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // to handle the file descriptor not being set. 2178c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook fileDescriptor = null; 21793c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21803c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (fileDescriptor != null) { 21823c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook result.putParcelable(attachment.contentUri.toString(), fileDescriptor); 21833c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21843c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 21853c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 21863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook return result; 21873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 218882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 218982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 219082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 219182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 219282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 219382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 219482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 219582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 219682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 219782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 219882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 219982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 220082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 220182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 220282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 220382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 220482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 220582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 220782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 221382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 221982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 222082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 222182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 222382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 222782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 2229ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) { 2230e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira if (mValidator == null) { 2231e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira return; 2232e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira } 2233ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final String email : to) { 223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 223582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 223682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 22402558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static class RecipientErrorDialogFragment extends DialogFragment { 22412558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static RecipientErrorDialogFragment newInstance(final String message) { 22422558b509117872e539a6eaeb72aa63425529d50bTony Mantler final RecipientErrorDialogFragment frag = new RecipientErrorDialogFragment(); 22432558b509117872e539a6eaeb72aa63425529d50bTony Mantler final Bundle args = new Bundle(1); 22442558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putString("message", message); 22452558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.setArguments(args); 22462558b509117872e539a6eaeb72aa63425529d50bTony Mantler return frag; 22472558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 22482558b509117872e539a6eaeb72aa63425529d50bTony Mantler 22492558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 22502558b509117872e539a6eaeb72aa63425529d50bTony Mantler public Dialog onCreateDialog(Bundle savedInstanceState) { 22512558b509117872e539a6eaeb72aa63425529d50bTony Mantler final String message = getArguments().getString("message"); 22522558b509117872e539a6eaeb72aa63425529d50bTony Mantler return new AlertDialog.Builder(getActivity()).setMessage(message).setTitle( 22532558b509117872e539a6eaeb72aa63425529d50bTony Mantler R.string.recipient_error_dialog_title) 22542558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setIconAttribute(android.R.attr.alertDialogIcon) 22552558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setPositiveButton( 22562558b509117872e539a6eaeb72aa63425529d50bTony Mantler R.string.ok, new Dialog.OnClickListener() { 22572558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 22582558b509117872e539a6eaeb72aa63425529d50bTony Mantler public void onClick(DialogInterface dialog, int which) { 22592558b509117872e539a6eaeb72aa63425529d50bTony Mantler ((ComposeActivity)getActivity()).finishRecipientErrorDialog(); 22602558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 22612558b509117872e539a6eaeb72aa63425529d50bTony Mantler }).create(); 22622558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 22632558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 22642558b509117872e539a6eaeb72aa63425529d50bTony Mantler 22652558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void finishRecipientErrorDialog() { 22662558b509117872e539a6eaeb72aa63425529d50bTony Mantler // after the user dismisses the recipient error 22672558b509117872e539a6eaeb72aa63425529d50bTony Mantler // dialog we want to make sure to refocus the 22682558b509117872e539a6eaeb72aa63425529d50bTony Mantler // recipient to field so they can fix the issue 22692558b509117872e539a6eaeb72aa63425529d50bTony Mantler // easily 22702558b509117872e539a6eaeb72aa63425529d50bTony Mantler if (mTo != null) { 22712558b509117872e539a6eaeb72aa63425529d50bTony Mantler mTo.requestFocus(); 22722558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 22732558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 22742558b509117872e539a6eaeb72aa63425529d50bTony Mantler 227582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 227682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 227782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 227882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 22792558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void showRecipientErrorDialog(final String message) { 22802558b509117872e539a6eaeb72aa63425529d50bTony Mantler final DialogFragment frag = RecipientErrorDialogFragment.newInstance(message); 22812558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.show(getFragmentManager(), "recipient error"); 228282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 228382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 228482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 228582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 228682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 228782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 2288eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 228982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 229082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 229182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 229282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 229382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 229482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 229582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 229682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 22987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 229982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 230182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 230282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 2303a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira // AND there is actually something in the draft to save. 2304d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang return (mTextChanged || mAttachmentsChanged || mReplyFromChanged) 2305a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira && !isBlank(); 230682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 230782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 230882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 230982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 2310bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 231182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 231282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 231382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 231482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 2315bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 2316bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 2317bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 2318bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 2319bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 2320bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2321bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2322bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 2323bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 2324bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 2325bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2326bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 2327bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 2328bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2329bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2330bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 2331bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 2332bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 2333bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 2334bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2335bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 2336bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 2337bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 2338bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 2339bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 2340bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 2341bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 2342bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 2343bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2344bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 234582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 234682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 234782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 234882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 234982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 235082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 235182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 235282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 2353eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 235482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 235533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 235633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 235782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 2358181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 2359181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 2360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 2361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 2363dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei final boolean orientationChanged, final boolean autoSend) { 2364009b3712ff1657fa839049826451321fdd938d32Mark Wei if (mAccounts == null || mAccount == null) { 2365009b3712ff1657fa839049826451321fdd938d32Mark Wei Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show(); 2366dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei if (autoSend) { 2367dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei finish(); 2368dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei } 2369009b3712ff1657fa839049826451321fdd938d32Mark Wei return false; 2370009b3712ff1657fa839049826451321fdd938d32Mark Wei } 2371009b3712ff1657fa839049826451321fdd938d32Mark Wei 2372ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final String[] to, cc, bcc; 2373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 2374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 2375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 2376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 2377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 2378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 2379181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2381181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 2382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 2383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 2384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 2385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 2386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 2389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 2391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 2392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 2393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 2396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 2397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 2398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 2399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 2400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 2401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 2404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 2406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 24072558b509117872e539a6eaeb72aa63425529d50bTony Mantler boolean emptyBody = TextUtils.getTrimmedLength(mBodyView.getEditableText()) == 0; 2408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 2410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 2411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 2412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 2413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 2415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 2416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 2417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 24182558b509117872e539a6eaeb72aa63425529d50bTony Mantler showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, save, 24192558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 2420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 24242558b509117872e539a6eaeb72aa63425529d50bTony Mantler showSendConfirmDialog(R.string.confirm_send_message_with_no_body, save, 24252558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 2426181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2427181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2428181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2429181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 2430181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 24312558b509117872e539a6eaeb72aa63425529d50bTony Mantler showSendConfirmDialog(R.string.confirm_send_message, save, showToast); 2432181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2433181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2434181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 24362558b509117872e539a6eaeb72aa63425529d50bTony Mantler sendOrSave(save, showToast); 2437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2439181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2440181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2441181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 2442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 24435c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang * 2444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 2445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2446181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 2447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 2448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2450181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2451181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 2452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 2453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 2454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 2456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 2457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2458181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 24592558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static class SendConfirmDialogFragment extends DialogFragment { 24602558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static SendConfirmDialogFragment newInstance(final int messageId, 24612558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean save, final boolean showToast) { 24622558b509117872e539a6eaeb72aa63425529d50bTony Mantler final SendConfirmDialogFragment frag = new SendConfirmDialogFragment(); 24632558b509117872e539a6eaeb72aa63425529d50bTony Mantler final Bundle args = new Bundle(3); 24642558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putInt("messageId", messageId); 24652558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putBoolean("save", save); 24662558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putBoolean("showToast", showToast); 24672558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.setArguments(args); 24682558b509117872e539a6eaeb72aa63425529d50bTony Mantler return frag; 2469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 24702558b509117872e539a6eaeb72aa63425529d50bTony Mantler 24712558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 24722558b509117872e539a6eaeb72aa63425529d50bTony Mantler public Dialog onCreateDialog(Bundle savedInstanceState) { 24732558b509117872e539a6eaeb72aa63425529d50bTony Mantler final int messageId = getArguments().getInt("messageId"); 24742558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean save = getArguments().getBoolean("save"); 24752558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean showToast = getArguments().getBoolean("showToast"); 24762558b509117872e539a6eaeb72aa63425529d50bTony Mantler 24772558b509117872e539a6eaeb72aa63425529d50bTony Mantler return new AlertDialog.Builder(getActivity()) 24782558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setMessage(messageId) 24792558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setTitle(R.string.confirm_send_title) 24802558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setIconAttribute(android.R.attr.alertDialogIcon) 24812558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setPositiveButton(R.string.send, 24822558b509117872e539a6eaeb72aa63425529d50bTony Mantler new DialogInterface.OnClickListener() { 2483aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 24842558b509117872e539a6eaeb72aa63425529d50bTony Mantler public void onClick(DialogInterface dialog, int whichButton) { 24852558b509117872e539a6eaeb72aa63425529d50bTony Mantler ((ComposeActivity)getActivity()).finishSendConfirmDialog(save, 24862558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 24872558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24882558b509117872e539a6eaeb72aa63425529d50bTony Mantler }) 24892558b509117872e539a6eaeb72aa63425529d50bTony Mantler .create(); 24902558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24912558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24922558b509117872e539a6eaeb72aa63425529d50bTony Mantler 24932558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void finishSendConfirmDialog(final boolean save, final boolean showToast) { 24942558b509117872e539a6eaeb72aa63425529d50bTony Mantler sendOrSave(save, showToast); 24952558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24962558b509117872e539a6eaeb72aa63425529d50bTony Mantler 24972558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void showSendConfirmDialog(final int messageId, final boolean save, 24982558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean showToast) { 24992558b509117872e539a6eaeb72aa63425529d50bTony Mantler final DialogFragment frag = SendConfirmDialogFragment.newInstance(messageId, save, 25002558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 25012558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.show(getFragmentManager(), "send confirm"); 2502181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2503181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2504181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2505181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 2506181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 2507181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 2508181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2509181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 2510181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 2511181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2512181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2513181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2514181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 2515181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 2516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 2517181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 2519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 2520181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 2521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 2522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 2525e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount, 252605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook Message message, final Message refMessage, Spanned body, final CharSequence quotedText, 252744a6339dd80f4b5b9e5d54567021698d92467c5emindyp SendOrSaveCallback callback, Handler handler, boolean save, int composeMode, 252844a6339dd80f4b5b9e5d54567021698d92467c5emindyp ReplyFromAccount draftAccount) { 2529b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final ContentValues values = new ContentValues(); 253029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 2531b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final String refMessageId = refMessage != null ? refMessage.uri.toString() : ""; 2532c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira 2533e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putToAddresses(values, message.getToAddresses()); 2534e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCcAddresses(values, message.getCcAddresses()); 2535e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putBccAddresses(values, message.getBccAddresses()); 253629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 25378960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy MessageModification.putCustomFromAddress(values, message.getFrom()); 253892551d057965689f1952faeb06763f0762bc717fMindy Pereira 2539e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putSubject(values, message.subject); 2540b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook // Make sure to remove only the composing spans from the Spannable before saving. 2541b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final String htmlBody = Html.toHtml(removeComposingSpans(body)); 254205b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook 254329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 254429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 254529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 2546e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 2547e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 2548e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 2549e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 255055271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook final int quoteStartPos = fullBody.length() + pos; 255155271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook fullBody.append(text); 255255271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook MessageModification.putQuoteStartPos(values, quoteStartPos); 255312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 2554e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 255529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 2556e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 2557e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 2558e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 2559e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 256029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 256129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 2562002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = getDraftType(composeMode); 256312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 2564c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (refMessage != null) { 2565c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyHtml)) { 2566c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 2567c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 2568c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyText)) { 2569c59dd8270215f97d39697dae9e69976bcfe3642bmindyp MessageModification.putBody(values, 2570c59dd8270215f97d39697dae9e69976bcfe3642bmindyp Utils.convertHtmlToPlainText(fullBody.toString()).toString()); 2571c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 2572c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } else { 2573c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 2574c59dd8270215f97d39697dae9e69976bcfe3642bmindyp MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString()) 2575c59dd8270215f97d39697dae9e69976bcfe3642bmindyp .toString()); 2576c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira } 2577e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putAttachments(values, message.getAttachments()); 257812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 257912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 258012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 25813c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount, 25823c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook values, refMessageId, message.getAttachments(), save); 258344a6339dd80f4b5b9e5d54567021698d92467c5emindyp SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback, 258444a6339dd80f4b5b9e5d54567021698d92467c5emindyp draftAccount); 258582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 2587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 2588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 2589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 259082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 2592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 259382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2594b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook /** 2595b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook * Removes any composing spans from the specified string. This will create a new 2596b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook * SpannableString instance, as to not modify the behavior of the EditText view. 2597b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook */ 2598b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook private static SpannableString removeComposingSpans(Spanned body) { 2599b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final SpannableString messageBody = new SpannableString(body); 2600b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook BaseInputConnection.removeComposingSpans(messageBody); 2601b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook return messageBody; 2602b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook } 2603b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook 2604002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira private static int getDraftType(int mode) { 2605002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = -1; 2606002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira switch (mode) { 2607002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.COMPOSE: 2608002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.COMPOSE; 2609002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2610002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY: 2611002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY; 2612002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2613002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY_ALL: 2614002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY_ALL; 2615002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2616002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.FORWARD: 2617002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.FORWARD; 2618002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2619002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2620002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira return draftType; 2621002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2622002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira 26232558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void sendOrSave(final boolean save, final boolean showToast) { 2624181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 2625181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 26263ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook if (ActivityManager.isUserAMonkey()) { 2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 262982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 26302558b509117872e539a6eaeb72aa63425529d50bTony Mantler final Spanned body = mBodyView.getEditableText(); 26312558b509117872e539a6eaeb72aa63425529d50bTony Mantler 2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 26331f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang // FIXME: unused 263482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 263582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 26360bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 263782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 2638181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 2639181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 2640181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 2641181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 2642181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 2643181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 2644181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2645181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2646181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 2647181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2648181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 2649181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 2650181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2651181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 265282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 26530bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 26547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 26557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 2656181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 265744a6339dd80f4b5b9e5d54567021698d92467c5emindyp mDraftAccount = sendOrSaveMessage.mAccount; 2658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 2659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 26607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 26617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 26627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 2664181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 2665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2666181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 26677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 2668181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2669181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 267082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 26710bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 26727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 26737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 26747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 26757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 26767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 267782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 26780bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 26797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 268047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // Update the last sent from account. 268147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (mAccount != null) { 268247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString()); 268347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 26847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 26857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 26867ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 26877ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 26887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 26897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 26907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 26917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 26927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 26937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 269482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 26957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 26967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 26977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 26987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 26997ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 27007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 270182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 27027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 27037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 27047ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 27057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 27067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 27077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 27087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 27097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 2711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Get the selected account if the from spinner has been setup. 271392551d057965689f1952faeb06763f0762bc717fMindy Pereira ReplyFromAccount selectedAccount = mReplyFromAccount; 2714181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String fromAddress = selectedAccount.name; 2715181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (selectedAccount == null || fromAddress == null) { 2716181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // We don't have either the selected account or from address, 2717181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // use mAccount. 271892551d057965689f1952faeb06763f0762bc717fMindy Pereira selectedAccount = mReplyFromAccount; 2719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira fromAddress = mAccount.name; 2720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 2723181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 2724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 2725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 2727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2729e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message msg = createMessage(mReplyFromAccount, getMode()); 273005b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body, 273105b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mQuotedTextView.getQuotedTextIfIncluded(), callback, 273244a6339dd80f4b5b9e5d54567021698d92467c5emindyp mSendSaveTaskHandler, save, mComposeMode, mDraftAccount); 2733181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2734181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mRecipient != null && mRecipient.equals(mAccount.name)) { 2735181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRecipient = selectedAccount.name; 2736181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2737b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(selectedAccount.account); 2738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2739181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 2740181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 2741181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 2742181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 2743181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 2744181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 2745181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2746181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2747181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 2748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 2749181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 2750181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 2751181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2752181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 2753181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2754181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 2755181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2756181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2757181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2758181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2759181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 2760181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 2761181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 2762181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2763181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 2764181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 2765181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 276682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 27672db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private void doAttach(String type) { 2768013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 2769013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 2770d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 27712db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira i.setType(type); 2772013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 2773181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 2774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 2775013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 2776013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 2777ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 2778a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 2779ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 2780cd0b0b950efebfc3964334067747b97e61c4f027mindyp mCcBccButton.setVisibility(View.INVISIBLE); 2781ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2782ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2783ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 2784326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2785326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 2786a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 2787326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 2788326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 2789326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 2790326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 2791326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 2792326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 2793326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2794cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira clearChangeListeners(); 2795a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 2796154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 279768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp if (mRefMessage != null) { 27980aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy setFieldsFromRefMessage(mComposeMode); 27998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 2800ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showCc = false; 2801ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showBcc = false; 2802ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mDraft != null) { 2803ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Following desktop behavior, if the user has added a BCC 2804ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // field to a draft, we show it regardless of compose mode. 28058960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy showBcc = !TextUtils.isEmpty(mDraft.getBcc()); 2806ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Use the draft to determine what to populate. 2807ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // If the Bcc field is showing, show the Cc field whether it is populated or not. 28088960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy showCc = showBcc 28098960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL); 281068c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp } 281168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp if (mRefMessage != null) { 28129b1ac57b10316cc1416c46f04811c54830e01529mindyp showCc = !TextUtils.isEmpty(mCc.getText()); 281368c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp showBcc = !TextUtils.isEmpty(mBcc.getText()); 2814ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } 2815ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 2816a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 2817ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira updateHideOrShowCcBcc(); 2818cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira initChangeListeners(); 2819326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 2820326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2821326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2822b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira @VisibleForTesting 2823b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira protected void resetMessageForModeChange() { 2824154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 2825154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 2826154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 2827154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 2828154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 2829154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 2830154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 2831154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 2832154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 2833154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 2834154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 2835154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 2836154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2837154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 2838154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 2839154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 2840154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 2841154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 2842154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 2843154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2844154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2845154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2846326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 2847326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2848326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 2849326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2850326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 2851326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 2852326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 2853326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2854326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2855326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 2856326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 2857326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 2858326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2859326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 2860326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2861326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2862326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2863326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 2864326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 2865326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 2866326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2867326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 2868326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 2869326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2870326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 287146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 287246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 287346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 287446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 287540882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(false); 28761623f9bfde8ced840a52820da28a0939bcaa32f9mindyp mRespondedInline = true; 287709dd373fae26156a847bb99d88474a7538b9e7c1mindyp if (!mBodyView.hasFocus()) { 28788654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp mBodyView.requestFocus(); 287909dd373fae26156a847bb99d88474a7538b9e7c1mindyp } 288046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 288146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 288246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 288346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 288446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 288546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 288646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 288746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 288846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 288946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 2890eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 289146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 289246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 289346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 289446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 289546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 289646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 289746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 289846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 289946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 2900bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 290146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 290246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 290346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 290446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 2905eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 2906bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 2907bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 2908bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2909bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2910bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2911bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 2912b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira String newSignature = mCachedSettings != null ? mCachedSettings.signature : null; 2913433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira boolean hasFocus = mBodyView.hasFocus(); 29142708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString()); 29152708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) { 2916b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mSignature = newSignature; 29172708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp if (!TextUtils.isEmpty(mSignature)) { 2918b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira // Appending a signature does not count as changing text. 2919b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.removeTextChangedListener(this); 2920b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 2921b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.addTextChangedListener(this); 2922b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira } 2923433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (hasFocus) { 2924433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 2925433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 2926bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2927bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2928bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2929bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 2930bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 2931bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 2932bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 2933bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2934bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 293546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 29361a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 29375a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 29385a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 293992551d057965689f1952faeb06763f0762bc717fMindy Pereira mReplyFromAccount = mFromSpinner.getCurrentAccount(); 294092551d057965689f1952faeb06763f0762bc717fMindy Pereira if (!mAccount.equals(mReplyFromAccount.account)) { 2941f432dbce53a73eabed150b35033f2ec1a70c9725mindyp // Clear a signature, if there was one. 2942f432dbce53a73eabed150b35033f2ec1a70c9725mindyp mBodyView.removeTextChangedListener(this); 2943f432dbce53a73eabed150b35033f2ec1a70c9725mindyp String oldSignature = mSignature; 2944f432dbce53a73eabed150b35033f2ec1a70c9725mindyp String bodyText = getBody().getText().toString(); 2945f432dbce53a73eabed150b35033f2ec1a70c9725mindyp if (!TextUtils.isEmpty(oldSignature)) { 2946f432dbce53a73eabed150b35033f2ec1a70c9725mindyp int pos = getSignatureStartPosition(oldSignature, bodyText); 2947f432dbce53a73eabed150b35033f2ec1a70c9725mindyp if (pos > -1) { 2948f432dbce53a73eabed150b35033f2ec1a70c9725mindyp mBodyView.setText(bodyText.substring(0, pos)); 2949f432dbce53a73eabed150b35033f2ec1a70c9725mindyp } 2950f432dbce53a73eabed150b35033f2ec1a70c9725mindyp } 2951b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(mReplyFromAccount.account); 2952f432dbce53a73eabed150b35033f2ec1a70c9725mindyp mBodyView.addTextChangedListener(this); 2953181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 2954181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 2955181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 2956181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 2957181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 2958181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2959181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 2960181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 296182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 29621a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 296382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 296482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 296582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 296682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 296782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 296882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 296982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 29702558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static class DiscardConfirmDialogFragment extends DialogFragment { 29712558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 29722558b509117872e539a6eaeb72aa63425529d50bTony Mantler public Dialog onCreateDialog(Bundle savedInstanceState) { 29732558b509117872e539a6eaeb72aa63425529d50bTony Mantler return new AlertDialog.Builder(getActivity()) 29742558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setMessage(R.string.confirm_discard_text) 29752558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setPositiveButton(R.string.discard, 29762558b509117872e539a6eaeb72aa63425529d50bTony Mantler new DialogInterface.OnClickListener() { 29772558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 29782558b509117872e539a6eaeb72aa63425529d50bTony Mantler public void onClick(DialogInterface dialog, int which) { 29792558b509117872e539a6eaeb72aa63425529d50bTony Mantler ((ComposeActivity)getActivity()).doDiscardWithoutConfirmation(); 29802558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 29812558b509117872e539a6eaeb72aa63425529d50bTony Mantler }) 29822b215b7e4aa5901322dd6ef2e4e8616a4552e9b3Tony Mantler .setNegativeButton(R.string.cancel, null) 29832558b509117872e539a6eaeb72aa63425529d50bTony Mantler .create(); 298482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 298582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 298682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2987efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 29882558b509117872e539a6eaeb72aa63425529d50bTony Mantler final DialogFragment frag = new DiscardConfirmDialogFragment(); 29892558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.show(getFragmentManager(), "discard confirm"); 2990efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 299182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 299282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 299382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 299482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 299582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 299682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 29972558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void doDiscardWithoutConfirmation() { 29987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 299982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 300082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 3001b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 300278ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) { 3003cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 3004cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 30050bbc858506c95005f2840fa5dff495a9216d2665Marc Blank getContentResolver().delete(mDraft.uri, null, null); 3006cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 300782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 300882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 300982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 301082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 301182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 301282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 301382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 301482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 30152558b509117872e539a6eaeb72aa63425529d50bTony Mantler // Display a toast to let the user know 30162558b509117872e539a6eaeb72aa63425529d50bTony Mantler Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 301782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 301882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 301982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 302082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 302182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 302282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 3023eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 3024eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 3025eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 3026eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 3027eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 3028eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 3029eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 3030eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 3031eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 303248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira doSave(!mAddingAttachment /* show toast */); 3033eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 3034eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 3035eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 3036eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 3037eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 3038eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 303940882430c874ff29890ec6fa31f7649788cbc470mindyp // If we are showing any attachments, make sure we have an upper 304040882430c874ff29890ec6fa31f7649788cbc470mindyp // divider. 304140882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 3042eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 3043eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 304475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 304540882430c874ff29890ec6fa31f7649788cbc470mindyp @Override 304640882430c874ff29890ec6fa31f7649788cbc470mindyp public void onAttachmentAdded() { 304740882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 304840882430c874ff29890ec6fa31f7649788cbc470mindyp mAttachmentsView.focusLastAttachment(); 304940882430c874ff29890ec6fa31f7649788cbc470mindyp } 305075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 305175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 305275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 305375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 30540bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 305575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 305675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 305775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 305875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 305975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 306075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 306175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 306275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 306375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 306475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 30650bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 306675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 306775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 306875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 306975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 307075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 307175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 307275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 307375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 307475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 307575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 307675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 307775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 307875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 307975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 308075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 308175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 308275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 308375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 308475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 308575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 308675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 308775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 308875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 308975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 309075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 309175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 309275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 309375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 309475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 309575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 309675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 309775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 309875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 309975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 310075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 310175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 310275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 310375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 310475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 310575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 310675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 310775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 310875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 310975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 311075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 311175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 311275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 311375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 311475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 311575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 311675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 311775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 311875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 311975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 312075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 312175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 312275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 312375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 312475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 312575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 312675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 312775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 312875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 312975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 313075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 313175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 313275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 313375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 313475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 313575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 313675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 313775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 313875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 313975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 314075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 314175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 314275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 314375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 314475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 3145e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 3146e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) { 3147e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (sTestSendOrSaveCallback != null && testCallback != null) { 3148e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira throw new IllegalStateException("Attempting to register more than one test callback"); 3149e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 3150e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira sTestSendOrSaveCallback = testCallback; 3151e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 3152bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira 3153bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira @VisibleForTesting 3154bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira protected ArrayList<Attachment> getAttachments() { 3155bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira return mAttachmentsView.getAttachments(); 3156bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira } 315796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 315896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 315996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public Loader<Cursor> onCreateLoader(int id, Bundle args) { 316096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira switch (id) { 3161a990a715012379451344246c5156d29938f12886Alice Yang case INIT_DRAFT_USING_REFERENCE_MESSAGE: 3162a990a715012379451344246c5156d29938f12886Alice Yang return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null, 3163a990a715012379451344246c5156d29938f12886Alice Yang null, null); 316496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira case REFERENCE_MESSAGE_LOADER: 316596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null, 316696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira null, null); 3167b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case LOADER_ACCOUNT_CURSOR: 3168b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return new CursorLoader(this, MailAppProvider.getAccountsUri(), 3169b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira UIProvider.ACCOUNTS_PROJECTION, null, null, null); 317096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 317196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return null; 317296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 317396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 317496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 317596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 3176b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira int id = loader.getId(); 3177b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira switch (id) { 3178a990a715012379451344246c5156d29938f12886Alice Yang case INIT_DRAFT_USING_REFERENCE_MESSAGE: 3179b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (data != null && data.moveToFirst()) { 3180b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mRefMessage = new Message(data); 3181b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Intent intent = getIntent(); 3182a990a715012379451344246c5156d29938f12886Alice Yang initFromRefMessage(mComposeMode); 3183a990a715012379451344246c5156d29938f12886Alice Yang finishSetup(mComposeMode, intent, null); 3184a990a715012379451344246c5156d29938f12886Alice Yang if (mComposeMode != FORWARD) { 3185b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira String to = intent.getStringExtra(EXTRA_TO); 3186b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (!TextUtils.isEmpty(to)) { 31870aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy mRefMessage.setTo(null); 31880aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy mRefMessage.setFrom(null); 3189b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira clearChangeListeners(); 3190b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mTo.append(to); 3191b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initChangeListeners(); 3192b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3193b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3194b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 3195b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 319696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 3197b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 3198a990a715012379451344246c5156d29938f12886Alice Yang case REFERENCE_MESSAGE_LOADER: 3199a990a715012379451344246c5156d29938f12886Alice Yang // Only populate mRefMessage and leave other fields untouched. 3200a990a715012379451344246c5156d29938f12886Alice Yang if (data != null && data.moveToFirst()) { 3201a990a715012379451344246c5156d29938f12886Alice Yang mRefMessage = new Message(data); 3202a990a715012379451344246c5156d29938f12886Alice Yang } 32039f855d667e34fbf0d330845225c26956e540b819Andy Huang finishSetup(mComposeMode, getIntent(), mInnerSavedState); 3204a990a715012379451344246c5156d29938f12886Alice Yang break; 3205b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case LOADER_ACCOUNT_CURSOR: 3206b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (data != null && data.moveToFirst()) { 3207b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // there are accounts now! 3208b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Account account; 3209faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook final ArrayList<Account> accounts = new ArrayList<Account>(); 3210faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook final ArrayList<Account> initializedAccounts = new ArrayList<Account>(); 3211b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira do { 3212b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = new Account(data); 3213dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook if (account.isAccountReady()) { 3214b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initializedAccounts.add(account); 3215b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3216b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira accounts.add(account); 3217b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } while (data.moveToNext()); 3218b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (initializedAccounts.size() > 0) { 3219b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.wait).setVisibility(View.GONE); 3220b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR); 3221b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.compose).setVisibility(View.VISIBLE); 3222faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook mAccounts = initializedAccounts.toArray( 3223faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook new Account[initializedAccounts.size()]); 3224faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook 3225b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishCreate(); 3226b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira invalidateOptionsMenu(); 3227b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 3228b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Show "waiting" 3229b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = accounts.size() > 0 ? accounts.get(0) : null; 3230b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira showWaitFragment(account); 3231b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3232b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3233b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 3234b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3235b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3236b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 3237b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void showWaitFragment(Account account) { 3238b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira WaitFragment fragment = getWaitFragment(); 3239b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (fragment != null) { 3240b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragment.updateAccount(account); 324196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } else { 3242b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.wait).setVisibility(View.VISIBLE); 3243b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira replaceFragment(WaitFragment.newInstance(account, true), 3244b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT); 324596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 324696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 324796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 3248b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private WaitFragment getWaitFragment() { 3249b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT); 3250b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3251b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 3252b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private int replaceFragment(Fragment fragment, int transition, String tag) { 3253b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 3254b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.setTransition(transition); 3255b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.replace(R.id.wait, fragment, tag); 3256b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira final int transactionId = fragmentTransaction.commitAllowingStateLoss(); 3257b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return transactionId; 3258b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3259b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 326096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 326196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public void onLoaderReset(Loader<Cursor> arg0) { 326296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // Do nothing. 326396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 326483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook 326583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook @Override 326683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook public Context getActivityContext() { 326783e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook return this; 326883e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook } 32691f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang} 3270