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; 37bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sappersteinimport android.content.res.Resources; 387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor; 396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri; 408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle; 4182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler; 4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread; 433c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport android.os.ParcelFileDescriptor; 441ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport android.os.Parcelable; 4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns; 4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable; 4782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html; 48ed9c2f0e9b6b7d7556c3d048c78c072c21e587a1mindypimport android.text.SpannableString; 4982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned; 50c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils; 5182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher; 5246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token; 53c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 543cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereiraimport android.view.Gravity; 5562d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.KeyEvent; 56326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater; 57b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu; 58b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater; 59b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem; 608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View; 618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener; 625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup; 63b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrookimport android.view.inputmethod.BaseInputConnection; 6462d3ec7f251f6f9a96a859a2702916d07f30a04amindypimport android.view.inputmethod.EditorInfo; 65326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 67433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText; 686349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 69013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 707b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 71c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 729f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantlerimport com.android.common.contacts.DataUsageStatUpdater; 735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView; 745680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.MailIntentService; 755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R; 76761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huangimport com.android.mail.analytics.Analytics; 771ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.browse.MessageHeaderView; 7840882430c874ff29890ec6fa31f7649788cbc470mindypimport com.android.mail.compose.AttachmentsView.AttachmentAddedOrDeletedListener; 799932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 805a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 8130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 8233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 8330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 8430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 855680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedyimport com.android.mail.providers.Folder; 8647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereiraimport com.android.mail.providers.MailAppProvider; 873ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 8882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 8992551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount; 90181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 9130e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 923ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 9312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 941ebc2db723ed29093d724eb5da906a496ee57224Alice Yangimport com.android.mail.ui.AttachmentTile.AttachmentPreview; 9583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrookimport com.android.mail.ui.FeedbackEnabledActivity; 96fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereiraimport com.android.mail.ui.MailActivity; 97b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereiraimport com.android.mail.ui.WaitFragment; 9892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 99434f294a3ae17a4f76342af38d6376f672a5d9edMark Weiimport com.android.mail.utils.AttachmentUtils; 100febd226e871263aeb21d436bee81eb2f7dec3d03mindypimport com.android.mail.utils.ContentProviderTask; 101b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 10230e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 10330e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 10446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 10582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 1064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 1078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 1083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.FileNotFoundException; 1093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrookimport java.io.IOException; 1108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 1118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 11246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 113bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 11446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 11575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 11646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 11746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 1181c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 119bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 12082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 12146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 12246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 1232558b509117872e539a6eaeb72aa63425529d50bTony Mantler RespondInlineListener, TextWatcher, 124a990a715012379451344246c5156d29938f12886Alice Yang AttachmentAddedOrDeletedListener, OnAccountChangedListener, 125a990a715012379451344246c5156d29938f12886Alice Yang LoaderManager.LoaderCallbacks<Cursor>, TextView.OnEditorActionListener, 126a990a715012379451344246c5156d29938f12886Alice Yang FeedbackEnabledActivity { 1276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 128bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static final int COMPOSE = -1; 129bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static final int REPLY = 0; 130bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static final int REPLY_ALL = 1; 131bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static final int FORWARD = 2; 132bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static final int EDIT_DRAFT = 3; 1336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 13596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira protected static final String EXTRA_ACTION = "action"; 1366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 137326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_CC = "showCc"; 138326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_BCC = "showBcc"; 1391623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private static final String EXTRA_RESPONDED_INLINE = "respondedInline"; 1401d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp private static final String EXTRA_SAVE_ENABLED = "saveEnabled"; 141a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira 1428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 150bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein /** 151bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein * Expected to be html formatted text. 152bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein */ 153bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein private static final String EXTRA_QUOTED_TEXT = "quotedText"; 154bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein 155d27b6ea7fcc68b2af200158fab341c6e98727144mindyp protected static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString"; 1569a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 15762066e47fe69c33b60ed970e46809ba81d044064Mark Wei private static final String EXTRA_ATTACHMENT_PREVIEWS = "attachmentPreviews"; 15862066e47fe69c33b60ed970e46809ba81d044064Mark Wei 1598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 160184ec73e169fa7c54e7f3c9459191dbe1702f3b4Tony Mantler @VisibleForTesting 161184ec73e169fa7c54e7f3c9459191dbe1702f3b4Tony Mantler protected static final String EXTRA_TO = "to"; 1628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 16560847256c691b2677772a46919038f9c600fecf7Scott Kennedy /** 16660847256c691b2677772a46919038f9c600fecf7Scott Kennedy * An optional extra containing a {@link ContentValues} of values to be added to 16760847256c691b2677772a46919038f9c600fecf7Scott Kennedy * {@link SendOrSaveMessage#mValues}. 16860847256c691b2677772a46919038f9c600fecf7Scott Kennedy */ 16960847256c691b2677772a46919038f9c600fecf7Scott Kennedy public static final String EXTRA_VALUES = "extra-values"; 17060847256c691b2677772a46919038f9c600fecf7Scott Kennedy 1718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 172bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC, 173bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein EXTRA_QUOTED_TEXT }; 1748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 17582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 17682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 17782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 17882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 17982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 18182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 18282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 18382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 18482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 18582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 18682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 1871f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang // FIXME: values in this map are never read. 18882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 1896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1906349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1916349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 195daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook public static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1966349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 197e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String EXTRA_ATTACHMENTS = "attachments"; 198f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1995680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy /** If set, we will clear notifications for this folder. */ 2005680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy public static final String EXTRA_NOTIFICATION_FOLDER = "extra-notification-folder"; 2015680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy 2023ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 20336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 204b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira // If this is a reply/forward then this extra will hold a uri we must query 205b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira // to get the original message. 206b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira protected static final String EXTRA_IN_REFERENCE_TO_MESSAGE_URI = "in-reference-to-message-uri"; 207434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei // If this is an action to edit an existing draft message, this extra will hold the 208bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 209bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 2104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 211b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 212013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 213013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 214013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 2158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 216e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 2178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 218e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount"; 219e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_REQUEST_ID = "requestId"; 220e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart"; 221176a1993ab15298de58f0cc988939b2cc1632689Paul Westbrook private static final String EXTRA_FOCUS_SELECTION_END = "focusSelectionEnd"; 222e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_MESSAGE = "extraMessage"; 22396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira private static final int REFERENCE_MESSAGE_LOADER = 0; 224b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private static final int LOADER_ACCOUNT_CURSOR = 1; 225a990a715012379451344246c5156d29938f12886Alice Yang private static final int INIT_DRAFT_USING_REFERENCE_MESSAGE = 2; 22647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira private static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount"; 227b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private static final String TAG_WAIT = "wait-fragment"; 2282db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private static final String MIME_TYPE_PHOTO = "image/*"; 2292db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private static final String MIME_TYPE_VIDEO = "video/*"; 2308e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 2319f855d667e34fbf0d330845225c26956e540b819Andy Huang private static final String KEY_INNER_SAVED_STATE = "compose_state"; 2329f855d667e34fbf0d330845225c26956e540b819Andy Huang 23382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 23482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 23582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 23682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 237c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 238c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 239c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 2408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 2418e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 2427b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 243746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein protected Account mAccount; 24459e69095bd558a1e6ae890ce79b7b848331d0cc6Tony Mantler protected ReplyFromAccount mReplyFromAccount; 245181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 24682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 249326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 250746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein protected int mComposeMode = -1; 25146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 25246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 25359e69095bd558a1e6ae890ce79b7b848331d0cc6Tony Mantler protected EditText mBodyView; 2541a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 2552eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 256eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 2571883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira @VisibleForTesting 2581883b346928322a9f045bc5b7426ddcd6af9beb3Mindy Pereira protected FromAddressSpinner mFromSpinner; 259013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 26182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 26282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 26382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 26482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 265b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira @VisibleForTesting 266b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira protected Message mRefMessage; 2677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 26944a6339dd80f4b5b9e5d54567021698d92467c5emindyp private ReplyFromAccount mDraftAccount; 2707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 27193b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp private View mPhotoAttachmentsButton; 27293b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp private View mVideoAttachmentsButton; 2733ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 274326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 275daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view. 276daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook */ 277daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private boolean mLaunchedFromEmail = false; 278cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mToListener; 279cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mCcListener; 280cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private RecipientTextWatcher mBccListener; 281b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira private Uri mRefMessageUri; 282a990a715012379451344246c5156d29938f12886Alice Yang private boolean mShowQuotedText = false; 283746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein protected Bundle mInnerSavedState; 28460847256c691b2677772a46919038f9c600fecf7Scott Kennedy private ContentValues mExtraValues = null; 285daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 2861623f9bfde8ced840a52820da28a0939bcaa32f9mindyp // Array of the outstanding send or save tasks. Access is synchronized 2871623f9bfde8ced840a52820da28a0939bcaa32f9mindyp // with the object itself 2881623f9bfde8ced840a52820da28a0939bcaa32f9mindyp /* package for testing */ 2891623f9bfde8ced840a52820da28a0939bcaa32f9mindyp @VisibleForTesting 2901623f9bfde8ced840a52820da28a0939bcaa32f9mindyp public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 2911623f9bfde8ced840a52820da28a0939bcaa32f9mindyp // FIXME: this variable is never read. related to sRequestMessageIdMap. 2921623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private int mRequestId; 2931623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private String mSignature; 2941623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private Account[] mAccounts; 2951623f9bfde8ced840a52820da28a0939bcaa32f9mindyp private boolean mRespondedInline; 296dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang private boolean mPerformedSendOrDiscard = false; 2971623f9bfde8ced840a52820da28a0939bcaa32f9mindyp 298daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook /** 299326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 300326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 3013ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 30260847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, message, EDIT_DRAFT, null, null, null, null, 30360847256c691b2677772a46919038f9c600fecf7Scott Kennedy null /* extraValues */); 304326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 305326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 3066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 3076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 3086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 30933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 31060847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, null, COMPOSE, null, null, null, null, null /* extraValues */); 3116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3126349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3136349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 3146349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 3156349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 3163de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein public static void composeToAddress(Context launcher, Account account, String toAddress) { 31760847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, null, COMPOSE, toAddress, null, null, null, 31860847256c691b2677772a46919038f9c600fecf7Scott Kennedy null /* extraValues */); 319bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } 320bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein 321bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein /** 322bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein * Can be called from a non-UI thread. 323bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein */ 324bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static void composeWithQuotedText(Context launcher, Account account, 32560847256c691b2677772a46919038f9c600fecf7Scott Kennedy String quotedText, String subject, final ContentValues extraValues) { 32660847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, null, COMPOSE, null, null, quotedText, subject, extraValues); 3273de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein } 3283de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein 3293de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein /** 3303de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein * Can be called from a non-UI thread. 3313de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sapperstein */ 332746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein public static void composeWithExtraValues(Context launcher, Account account, 333746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein String subject, final ContentValues extraValues) { 334746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein launch(launcher, account, null, COMPOSE, null, null, null, subject, extraValues); 335746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein } 336746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein 337746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein /** 338746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein * Can be called from a non-UI thread. 339746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein */ 3400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy public static Intent createReplyIntent(final Context launcher, final Account account, 3410aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Uri messageUri, final boolean isReplyAll) { 3420aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy return createActionIntent(launcher, account, messageUri, isReplyAll ? REPLY_ALL : REPLY); 3430aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy } 3440aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3450aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy /** 3460aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy * Can be called from a non-UI thread. 3470aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy */ 3480aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy public static Intent createForwardIntent(final Context launcher, final Account account, 3490aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Uri messageUri) { 3500aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy return createActionIntent(launcher, account, messageUri, FORWARD); 3510aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy } 3520aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3530aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy private static Intent createActionIntent(final Context launcher, final Account account, 3540aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Uri messageUri, final int action) { 3550aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy final Intent intent = new Intent(launcher, ComposeActivity.class); 3560aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3576d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook updateActionIntent(account, messageUri, action, intent); 3586d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook 3596d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook return intent; 3606d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook } 3616d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook 3626d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook @VisibleForTesting 3636d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook static Intent updateActionIntent(Account account, Uri messageUri, int action, Intent intent) { 3640aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 3650aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(EXTRA_ACTION, action); 3660aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(Utils.EXTRA_ACCOUNT, account); 3670aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI, messageUri); 3680aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy return intent; 3700aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy } 3710aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy 3720aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy /** 3730aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy * Can be called from a non-UI thread. 3740aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy */ 3753ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 37660847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, message, REPLY, null, null, null, null, null /* extraValues */); 3776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3786349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 3806349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 3816349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 3823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 38360847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, message, REPLY_ALL, null, null, null, null, 38460847256c691b2677772a46919038f9c600fecf7Scott Kennedy null /* extraValues */); 3856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3876349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 3886349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 3896349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 3903ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 39160847256c691b2677772a46919038f9c600fecf7Scott Kennedy launch(launcher, account, message, FORWARD, null, null, null, null, null /* extraValues */); 3926349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 3936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 3941ebc2db723ed29093d724eb5da906a496ee57224Alice Yang public static void reportRenderingFeedback(Context launcher, Account account, Message message, 3951ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String body) { 396bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein launch(launcher, account, message, FORWARD, 39760847256c691b2677772a46919038f9c600fecf7Scott Kennedy "android-gmail-readability@google.com", body, null, null, null /* extraValues */); 3981ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 3991ebc2db723ed29093d724eb5da906a496ee57224Alice Yang 4001ebc2db723ed29093d724eb5da906a496ee57224Alice Yang private static void launch(Context launcher, Account account, Message message, int action, 40160847256c691b2677772a46919038f9c600fecf7Scott Kennedy String toAddress, String body, String quotedText, String subject, 40260847256c691b2677772a46919038f9c600fecf7Scott Kennedy final ContentValues extraValues) { 4036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 4046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 4056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 4066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 407bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 408bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 409bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 410bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 411bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 4121ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (toAddress != null) { 4131ebc2db723ed29093d724eb5da906a496ee57224Alice Yang intent.putExtra(EXTRA_TO, toAddress); 4141ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 4151ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (body != null) { 4161ebc2db723ed29093d724eb5da906a496ee57224Alice Yang intent.putExtra(EXTRA_BODY, body); 4171ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 418bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein if (quotedText != null) { 419bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein intent.putExtra(EXTRA_QUOTED_TEXT, quotedText); 420bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } 421bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein if (subject != null) { 422bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein intent.putExtra(EXTRA_SUBJECT, subject); 423bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } 42460847256c691b2677772a46919038f9c600fecf7Scott Kennedy if (extraValues != null) { 42560847256c691b2677772a46919038f9c600fecf7Scott Kennedy LogUtils.d(LOG_TAG, "Launching with extraValues: %s", extraValues.toString()); 42660847256c691b2677772a46919038f9c600fecf7Scott Kennedy intent.putExtra(EXTRA_VALUES, extraValues); 42760847256c691b2677772a46919038f9c600fecf7Scott Kennedy } 4286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 4296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 4308e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 4318e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 432d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy protected void onCreate(Bundle savedInstanceState) { 4338e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 4348e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 4359f855d667e34fbf0d330845225c26956e540b819Andy Huang mInnerSavedState = (savedInstanceState != null) ? 4369f855d667e34fbf0d330845225c26956e540b819Andy Huang savedInstanceState.getBundle(KEY_INNER_SAVED_STATE) : null; 437b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira checkValidAccounts(); 438b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 439b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 440b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void finishCreate() { 4419f855d667e34fbf0d330845225c26956e540b819Andy Huang final Bundle savedState = mInnerSavedState; 44246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 443818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 444e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message; 44562066e47fe69c33b60ed970e46809ba81d044064Mark Wei ArrayList<AttachmentPreview> previews; 446a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = false; 447bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein CharSequence quotedText = null; 448e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int action; 44947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // Check for any of the possibly supplied accounts.; 45047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Account account = null; 4519f855d667e34fbf0d330845225c26956e540b819Andy Huang if (hadSavedInstanceStateMessage(savedState)) { 4529f855d667e34fbf0d330845225c26956e540b819Andy Huang action = savedState.getInt(EXTRA_ACTION, COMPOSE); 4539f855d667e34fbf0d330845225c26956e540b819Andy Huang account = savedState.getParcelable(Utils.EXTRA_ACCOUNT); 4549f855d667e34fbf0d330845225c26956e540b819Andy Huang message = (Message) savedState.getParcelable(EXTRA_MESSAGE); 45562066e47fe69c33b60ed970e46809ba81d044064Mark Wei 4569f855d667e34fbf0d330845225c26956e540b819Andy Huang previews = savedState.getParcelableArrayList(EXTRA_ATTACHMENT_PREVIEWS); 4579f855d667e34fbf0d330845225c26956e540b819Andy Huang mRefMessage = (Message) savedState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE); 458bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein quotedText = savedState.getCharSequence(EXTRA_QUOTED_TEXT); 45944d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy 46044d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy mExtraValues = savedState.getParcelable(EXTRA_VALUES); 461e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 46247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = obtainAccount(intent); 463e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 464e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // Initialize the message from the message in the intent 465e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 46662066e47fe69c33b60ed970e46809ba81d044064Mark Wei previews = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENT_PREVIEWS); 467e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 468b18e5a9341c73541d7201830c513cb0ed247e935Mindy Pereira mRefMessageUri = (Uri) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE_URI); 4694fe0af81874976a1995191321e35c844b2229811Andy Huang 4704fe0af81874976a1995191321e35c844b2229811Andy Huang if (Analytics.isLoggable()) { 4714fe0af81874976a1995191321e35c844b2229811Andy Huang if (intent.getBooleanExtra(Utils.EXTRA_FROM_NOTIFICATION, false)) { 4724fe0af81874976a1995191321e35c844b2229811Andy Huang Analytics.getInstance().sendEvent( 4734fe0af81874976a1995191321e35c844b2229811Andy Huang "notification_action", "compose", getActionString(action), 0); 4744fe0af81874976a1995191321e35c844b2229811Andy Huang } 4754fe0af81874976a1995191321e35c844b2229811Andy Huang } 476e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 47762066e47fe69c33b60ed970e46809ba81d044064Mark Wei mAttachmentsView.setAttachmentPreviews(previews); 47892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 47992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 480818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 481818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 482818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 483bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 484fe853d3427119202562519c2add6873590851705Scott Kennedy initRecipients(); 485fe853d3427119202562519c2add6873590851705Scott Kennedy 4865680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy // Clear the notification and mark the conversation as seen, if necessary 4875680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy final Folder notificationFolder = 4885680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy intent.getParcelableExtra(EXTRA_NOTIFICATION_FOLDER); 4895680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy if (notificationFolder != null) { 4905680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy final Intent clearNotifIntent = 4915680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy new Intent(MailIntentService.ACTION_CLEAR_NEW_MAIL_NOTIFICATIONS); 492d5edd2d02649dffb40065fdb6a16acf91552b800Scott Kennedy clearNotifIntent.setPackage(getPackageName()); 49348cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy clearNotifIntent.putExtra(Utils.EXTRA_ACCOUNT, account); 49448cfe4613549cafdf36e2a524afba730522bf291Scott Kennedy clearNotifIntent.putExtra(Utils.EXTRA_FOLDER, notificationFolder); 4955680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy 4965680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy startService(clearNotifIntent); 4975680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy } 4985680ec22f92125cbd95ff0f8d18d5cc04c6f0b81Scott Kennedy 499daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) { 500daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = true; 501daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } else if (Intent.ACTION_SEND.equals(intent.getAction())) { 502daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final Uri dataUri = intent.getData(); 503daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (dataUri != null) { 504daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String dataScheme = intent.getData().getScheme(); 505daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String accountScheme = mAccount.composeIntentUri.getScheme(); 506daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme); 507daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 508daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 509daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 51096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira if (mRefMessageUri != null) { 511a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = true; 512a990a715012379451344246c5156d29938f12886Alice Yang mComposeMode = action; 513a990a715012379451344246c5156d29938f12886Alice Yang getLoaderManager().initLoader(INIT_DRAFT_USING_REFERENCE_MESSAGE, null, this); 51496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return; 51596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } else if (message != null && action != EDIT_DRAFT) { 516e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 517e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 5189f855d667e34fbf0d330845225c26956e540b819Andy Huang showCcBcc(savedState); 519a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = message.appendRefMessageContent; 520bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein // if we should be showing quoted text but mRefMessage is null 521bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein // and we have some quotedText, display that 522746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein if (mShowQuotedText && mRefMessage == null) { 523746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein if (quotedText != null) { 524746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein initQuotedText(quotedText, false /* shouldQuoteText */); 525746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein } else if (mExtraValues != null) { 526746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein initExtraValues(mExtraValues); 527746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein return; 528746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein } 529bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } 530e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (action == EDIT_DRAFT) { 531e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 5328960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy boolean showBcc = !TextUtils.isEmpty(message.getBcc()); 5338960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy boolean showCc = showBcc || !TextUtils.isEmpty(message.getCc()); 534ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 535bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 536bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 537bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 538bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 539bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 540bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 541bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 542bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 543bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 544bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 545bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 546bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 547bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 548bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 549bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 550bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 551a990a715012379451344246c5156d29938f12886Alice Yang LogUtils.d(LOG_TAG, "Previous draft had action type: %d", action); 552a990a715012379451344246c5156d29938f12886Alice Yang 553a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = message.appendRefMessageContent; 554a990a715012379451344246c5156d29938f12886Alice Yang if (message.refMessageUri != null) { 555a990a715012379451344246c5156d29938f12886Alice Yang // If we're editing an existing draft that was in reference to an existing message, 556a990a715012379451344246c5156d29938f12886Alice Yang // still need to load that original message since we might need to refer to the 557a990a715012379451344246c5156d29938f12886Alice Yang // original sender and recipients if user switches "reply <-> reply-all". 558a990a715012379451344246c5156d29938f12886Alice Yang mRefMessageUri = message.refMessageUri; 559a990a715012379451344246c5156d29938f12886Alice Yang mComposeMode = action; 560a990a715012379451344246c5156d29938f12886Alice Yang getLoaderManager().initLoader(REFERENCE_MESSAGE_LOADER, null, this); 561a990a715012379451344246c5156d29938f12886Alice Yang return; 562a990a715012379451344246c5156d29938f12886Alice Yang } 563e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 564e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 5650aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy initFromRefMessage(action); 566a990a715012379451344246c5156d29938f12886Alice Yang mShowQuotedText = true; 567e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 5688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 569746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein if (initFromExtras(intent)) { 570746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein return; 571746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein } 572bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 573a990a715012379451344246c5156d29938f12886Alice Yang 574a990a715012379451344246c5156d29938f12886Alice Yang mComposeMode = action; 5759f855d667e34fbf0d330845225c26956e540b819Andy Huang finishSetup(action, intent, savedState); 57696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 577bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 578b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void checkValidAccounts() { 579faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook final Account[] allAccounts = AccountUtils.getAccounts(this); 580faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook if (allAccounts == null || allAccounts.length == 0) { 581b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira final Intent noAccountIntent = MailAppProvider.getNoAccountIntent(this); 582b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (noAccountIntent != null) { 583faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook mAccounts = null; 584b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira startActivityForResult(noAccountIntent, RESULT_CREATE_ACCOUNT); 585b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 586b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 58726d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp // If none of the accounts are syncing, setup a watcher. 588b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira boolean anySyncing = false; 589faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook for (Account a : allAccounts) { 590dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook if (a.isAccountReady()) { 591b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira anySyncing = true; 592b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 593b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 594b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 595b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (!anySyncing) { 596b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // There are accounts, but none are sync'd, which is just like having no accounts. 597b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAccounts = null; 598b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); 599b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return; 600b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 601faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook mAccounts = AccountUtils.getSyncingAccounts(this); 602b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishCreate(); 603b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 604b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 605b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 60647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira private Account obtainAccount(Intent intent) { 60747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Account account = null; 60847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira Object accountExtra = null; 60947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (intent != null && intent.getExtras() != null) { 61047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = intent.getExtras().get(Utils.EXTRA_ACCOUNT); 61147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (accountExtra instanceof Account) { 61247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira return (Account) accountExtra; 6137ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp } else if (accountExtra instanceof String) { 6147ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp // This is the Account attached to the widget compose intent. 6157ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp account = Account.newinstance((String)accountExtra); 6167ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp if (account != null) { 6177ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp return account; 6187ae042ef2a23bf4c87f3edfcd71f7ebc784174abmindyp } 61947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 6205ee9dc48884714e9005a1409e7002a0e04bad313mindyp accountExtra = intent.hasExtra(Utils.EXTRA_ACCOUNT) ? 6215ee9dc48884714e9005a1409e7002a0e04bad313mindyp intent.getStringExtra(Utils.EXTRA_ACCOUNT) : 6225ee9dc48884714e9005a1409e7002a0e04bad313mindyp intent.getStringExtra(EXTRA_SELECTED_ACCOUNT); 62347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 62447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (account == null) { 6250617446db14891bffaa2748e1fc98526aac1e06dmindyp MailAppProvider provider = MailAppProvider.getInstance(); 6260617446db14891bffaa2748e1fc98526aac1e06dmindyp String lastAccountUri = provider.getLastSentFromAccount(); 6270617446db14891bffaa2748e1fc98526aac1e06dmindyp if (TextUtils.isEmpty(lastAccountUri)) { 6280617446db14891bffaa2748e1fc98526aac1e06dmindyp lastAccountUri = provider.getLastViewedAccount(); 6290617446db14891bffaa2748e1fc98526aac1e06dmindyp } 63047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (!TextUtils.isEmpty(lastAccountUri)) { 63147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira accountExtra = Uri.parse(lastAccountUri); 63247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 63347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 634b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts != null && mAccounts.length > 0) { 63547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (accountExtra instanceof String && !TextUtils.isEmpty((String) accountExtra)) { 63647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // For backwards compatibility, we need to check account 63747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // names. 638b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 63979b1156803585952a4851221dc9fa9974e606433Tony Mantler if (a.getEmailAddress().equals(accountExtra)) { 64047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = a; 64147d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 64247d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 64347d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } else if (accountExtra instanceof Uri) { 64447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // The uri of the last viewed account is what is stored in 64547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // the current code base. 646b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira for (Account a : mAccounts) { 64747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (a.uri.equals(accountExtra)) { 64847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira account = a; 64947d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 65047d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 651b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 652b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (account == null) { 653b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = mAccounts[0]; 65447d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 65547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 65647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira return account; 65747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 65847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira 659746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein protected void finishSetup(int action, Intent intent, Bundle savedInstanceState) { 66034a3c56570eac4760405b3d5bff5fdc706a22facmindyp setFocus(action); 661f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // Don't bother with the intent if we have procured a message from the 662f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // intent already. 663f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira if (!hadSavedInstanceStateMessage(savedInstanceState)) { 664f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira initAttachmentsFromIntent(intent); 665f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 666a990a715012379451344246c5156d29938f12886Alice Yang initActionBar(); 667e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(), 668e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action); 669d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp 670d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp // If this is a draft message, the draft account is whatever account was 671d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp // used to open the draft message in Compose. 672d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp if (mDraft != null) { 673d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp mDraftAccount = mReplyFromAccount; 674d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp } 675d4a4866c99ae0ed8c943b6c9ced1e7fbc987c639mindyp 67675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 677326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira updateHideOrShowCcBcc(); 678a990a715012379451344246c5156d29938f12886Alice Yang updateHideOrShowQuotedText(mShowQuotedText); 6791623f9bfde8ced840a52820da28a0939bcaa32f9mindyp 6809f855d667e34fbf0d330845225c26956e540b819Andy Huang mRespondedInline = mInnerSavedState != null ? 6819f855d667e34fbf0d330845225c26956e540b819Andy Huang mInnerSavedState.getBoolean(EXTRA_RESPONDED_INLINE) : false; 6821623f9bfde8ced840a52820da28a0939bcaa32f9mindyp if (mRespondedInline) { 6831623f9bfde8ced840a52820da28a0939bcaa32f9mindyp mQuotedTextView.setVisibility(View.GONE); 6841623f9bfde8ced840a52820da28a0939bcaa32f9mindyp } 68571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira } 68671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira 687ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static boolean hadSavedInstanceStateMessage(final Bundle savedInstanceState) { 688f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE); 689f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 690f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira 69171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira private void updateHideOrShowQuotedText(boolean showQuotedText) { 69271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira mQuotedTextView.updateCheckedState(showQuotedText); 69340882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 694433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 695433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 696433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private void setFocus(int action) { 697433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (action == EDIT_DRAFT) { 698433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int type = mDraft.draftType; 699433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (type) { 700433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.COMPOSE: 701433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.FORWARD: 702433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = COMPOSE; 703433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 704433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY: 705433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY_ALL: 706433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 707433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = REPLY; 708433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 709433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 710433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 711433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (action) { 712433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case FORWARD: 713433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case COMPOSE: 7142708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp if (TextUtils.isEmpty(mTo.getText())) { 7152708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp mTo.requestFocus(); 7162708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp break; 7172708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp } 718ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy //$FALL-THROUGH$ 719433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY: 720433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY_ALL: 721433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 722433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 723433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 724433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 725433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 726433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 727433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira /** 728433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira * Focus the body of the message. 729433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira */ 730433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira public void focusBody() { 731433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.requestFocus(); 732433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int length = mBodyView.getText().length(); 733433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 734433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int signatureStartPos = getSignatureStartPosition( 735433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mSignature, mBodyView.getText().toString()); 736433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (signatureStartPos > -1) { 737433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // In case the user deleted the newlines... 738433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(signatureStartPos); 7398743cfca851058d50385951b111dd903b1fa6c5amindyp } else if (length >= 0) { 740433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // Move cursor to the end. 741433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(length); 742433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 7431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 7441a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 7451a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 746761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang protected void onStart() { 747761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang super.onStart(); 748761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 749761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().activityStart(this); 750761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang } 751761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 752761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang @Override 753761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang protected void onStop() { 754761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang super.onStop(); 755761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 756761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang Analytics.getInstance().activityStop(this); 757761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang } 758761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang 759761522c1ac7a8fa05acde714f0e26fde47f3415fAndy Huang @Override 7601a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 7611a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 7621a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 7631a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 764818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 765c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromSpinner.initialize(mComposeMode, mAccount, mAccounts, mRefMessage); 766818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 7671a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 7681a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 769eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 770eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 771eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 772eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 773a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira // When the user exits the compose view, see if this draft needs saving. 7743d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee // Don't save unnecessary drafts if we are only changing the orientation. 7753d7048ea243df4c1ae163bd72971e83e1218e7f0Yorke Lee if (!isChangingConfigurations()) { 776a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira saveIfNeeded(); 777dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang 778e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang if (isFinishing() && !mPerformedSendOrDiscard && !isBlank()) { 779dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang // log saving upon backing out of activity. (we avoid logging every sendOrSave() 780dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang // because that method can be invoked many times in a single compose session.) 781dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang logSendOrSave(true /* save */); 782dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang } 783a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira } 784eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 785eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 786eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 787eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 788b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (request == RESULT_PICK_ATTACHMENT && result == RESULT_OK) { 789eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 790b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mAddingAttachment = false; 791b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else if (request == RESULT_CREATE_ACCOUNT) { 792a990a715012379451344246c5156d29938f12886Alice Yang // We were waiting for the user to create an account 793b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (result != RESULT_OK) { 794b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 795b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 796b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Watch for accounts to show up! 797b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // restart the loader to get the updated list of accounts 798b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().initLoader(LOADER_ACCOUNT_CURSOR, null, this); 799b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira showWaitFragment(null); 800b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 801eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 802eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 803eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 804eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 805d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy protected final void onRestoreInstanceState(Bundle savedInstanceState) { 8067bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee final boolean hasAccounts = mAccounts != null && mAccounts.length > 0; 8077bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee if (hasAccounts) { 8087bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee clearChangeListeners(); 8097bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee } 810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira super.onRestoreInstanceState(savedInstanceState); 8119f855d667e34fbf0d330845225c26956e540b819Andy Huang if (mInnerSavedState != null) { 8129f855d667e34fbf0d330845225c26956e540b819Andy Huang if (mInnerSavedState.containsKey(EXTRA_FOCUS_SELECTION_START)) { 8139f855d667e34fbf0d330845225c26956e540b819Andy Huang int selectionStart = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_START); 8149f855d667e34fbf0d330845225c26956e540b819Andy Huang int selectionEnd = mInnerSavedState.getInt(EXTRA_FOCUS_SELECTION_END); 815e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // There should be a focus and it should be an EditText since we 816e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // only save these extras if these conditions are true. 817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) getCurrentFocus(); 818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira final int length = focusEditText.getText().length(); 819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectionStart < length && selectionEnd < length) { 820e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira focusEditText.setSelection(selectionStart, selectionEnd); 821e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 822e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 8247bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee if (hasAccounts) { 8257bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee initChangeListeners(); 8267bec2b909cb5bba3bf9aae7e977fb1c8931f7230Yorke Lee } 827e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 828e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 829e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira @Override 830d90639004a3551d7fb7086f318d4c576d54d2b86Scott Kennedy protected final void onSaveInstanceState(Bundle state) { 831eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 8329f855d667e34fbf0d330845225c26956e540b819Andy Huang final Bundle inner = new Bundle(); 8339f855d667e34fbf0d330845225c26956e540b819Andy Huang saveState(inner); 8349f855d667e34fbf0d330845225c26956e540b819Andy Huang state.putBundle(KEY_INNER_SAVED_STATE, inner); 8359f855d667e34fbf0d330845225c26956e540b819Andy Huang } 8369f855d667e34fbf0d330845225c26956e540b819Andy Huang 8379f855d667e34fbf0d330845225c26956e540b819Andy Huang private void saveState(Bundle state) { 838b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // We have no accounts so there is nothing to compose, and therefore, nothing to save. 839b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 840b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return; 841b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 842e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // The framework is happy to save and restore the selection but only if it also saves and 843e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // restores the contents of the edit text. That's a lot of text to put in a bundle so we do 844e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // this manually. 845e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira View focus = getCurrentFocus(); 846e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (focus != null && focus instanceof EditText) { 847e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) focus; 848e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart()); 849e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd()); 850e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 8516273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook 8526273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 853151f1ad1613ecac0207144472872440517172b5aPaul Westbrook final int selectedPos = mFromSpinner.getSelectedItemPosition(); 854d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira final ReplyFromAccount selectedReplyFromAccount = (replyFromAccounts != null 855d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira && replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ? 856d90f7ac9b1a62e8beefdac3ceda9e4cb75ef000cMindy Pereira replyFromAccounts.get(selectedPos) : null; 857e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectedReplyFromAccount != null) { 858e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize() 859e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .toString()); 860e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account); 861e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 862e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount); 863e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 864eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 865e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) { 866e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We don't have a draft id, and we have a request id, 867e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // save the request id. 868e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_REQUEST_ID, mRequestId); 869e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 870e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 871e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We want to restore the current mode after a pause 872e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // or rotation. 873e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = getMode(); 874e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_ACTION, mode); 875e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 876e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp final Message message = createMessage(selectedReplyFromAccount, mode); 8771f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang if (mDraft != null) { 878e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp message.id = mDraft.id; 879e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp message.serverId = mDraft.serverId; 880e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp message.uri = mDraft.uri; 8811f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang } 882e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_MESSAGE, message); 883e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 884e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 885e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage); 886bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } else if (message.appendRefMessageContent) { 887bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein // If we have no ref message but should be appending 888bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein // ref message content, we have orphaned quoted text. Save it. 889bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein state.putCharSequence(EXTRA_QUOTED_TEXT, mQuotedTextView.getQuotedTextIfIncluded()); 890e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 891326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible()); 892326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible()); 8931623f9bfde8ced840a52820da28a0939bcaa32f9mindyp state.putBoolean(EXTRA_RESPONDED_INLINE, mRespondedInline); 894816b3f0adc04db073820f04ce379e5126e1cbef1mindyp state.putBoolean(EXTRA_SAVE_ENABLED, mSave != null && mSave.isEnabled()); 89562066e47fe69c33b60ed970e46809ba81d044064Mark Wei state.putParcelableArrayList( 89662066e47fe69c33b60ed970e46809ba81d044064Mark Wei EXTRA_ATTACHMENT_PREVIEWS, mAttachmentsView.getAttachmentPreviews()); 89744d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy 89844d4481f7cf9adf48820bd2c63cb35f98f9b12fdScott Kennedy state.putParcelable(EXTRA_VALUES, mExtraValues); 899e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 900e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 901e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private int getMode() { 902e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = ComposeActivity.COMPOSE; 903e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ActionBar actionBar = getActionBar(); 904e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar != null 905e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) { 906e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mode = actionBar.getSelectedNavigationIndex(); 907e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 908e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return mode; 909e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 910e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 911e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) { 912e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = new Message(); 913e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.id = UIProvider.INVALID_MESSAGE_ID; 914d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang message.serverId = null; 915e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.uri = null; 916e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.conversationUri = null; 917e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.subject = mSubject.getText().toString(); 918e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.snippet = null; 9198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setTo(formatSenders(mTo.getText().toString())); 9208960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setCc(formatSenders(mCc.getText().toString())); 9218960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setBcc(formatSenders(mBcc.getText().toString())); 9228960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy message.setReplyTo(null); 923e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.dateReceivedMs = 0; 924b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final String htmlBody = Html.toHtml(removeComposingSpans(mBodyView.getText())); 925b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final StringBuilder fullBody = new StringBuilder(htmlBody); 926e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyHtml = fullBody.toString(); 927e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyText = mBodyView.getText().toString(); 928e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.embedsExternalResources = false; 929a990a715012379451344246c5156d29938f12886Alice Yang message.refMessageUri = mRefMessage != null ? mRefMessage.uri : null; 930e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null; 931e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ArrayList<Attachment> attachments = mAttachmentsView.getAttachments(); 932e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.hasAttachments = attachments != null && attachments.size() > 0; 933e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentListUri = null; 934e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.messageFlags = 0; 935e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.alwaysShowImages = false; 936e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentsJson = Attachment.toJSONArray(attachments); 937e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira CharSequence quotedText = mQuotedTextView.getQuotedText(); 938e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView 939e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .getQuotedTextOffset(quotedText.toString()) : -1; 940e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.accountUri = null; 941bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler final String email = selectedReplyFromAccount != null ? selectedReplyFromAccount.address 942bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler : mAccount != null ? mAccount.getEmailAddress() : null; 943bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler // TODO: this behavior is wrong. Pull the name from selectedReplyFromAccount.name 944bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler final String senderName = mAccount != null ? mAccount.getSenderName() : null; 945bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler final Address address = new Address(senderName, email); 946bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler message.setFrom(address.pack()); 9471f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang message.draftType = getDraftType(mode); 948e7b76aac2ad5b12d6b04838ca72011ceaedc8910mindyp return message; 9491f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang } 9501f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang 951ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static String formatSenders(final String string) { 9523c9115813343861a44133b805fb9f55512d20948Mindy Pereira if (!TextUtils.isEmpty(string) && string.charAt(string.length() - 1) == ',') { 9533c9115813343861a44133b805fb9f55512d20948Mindy Pereira return string.substring(0, string.length() - 1); 9543c9115813343861a44133b805fb9f55512d20948Mindy Pereira } 9553c9115813343861a44133b805fb9f55512d20948Mindy Pereira return string; 9563c9115813343861a44133b805fb9f55512d20948Mindy Pereira } 9573c9115813343861a44133b805fb9f55512d20948Mindy Pereira 958818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 959818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 960bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira if (account == null) { 961bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira return; 962bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira } 96323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 96423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 965b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook mCachedSettings = mAccount.settings; 966b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook appendSignature(); 96723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 968fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira if (mAccount != null) { 96979b1156803585952a4851221dc9fa9974e606433Tony Mantler MailActivity.setNfcMessage(mAccount.getEmailAddress()); 970fa20c1a4e36e0da2577baddbbb38a988b2017339Mindy Pereira } 971818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 972818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 973e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromSpinner(Bundle bundle, int action) { 974e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) { 97562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira action = COMPOSE; 97662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 977c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromSpinner.initialize(action, mAccount, mAccounts, mRefMessage); 978c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook 9799a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle != null) { 9809a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) { 9819a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = ReplyFromAccount.deserialize(mAccount, 9829a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)); 9839a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) { 984c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook final String accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING); 9859a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString); 9869a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } 987e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 988e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mReplyFromAccount == null) { 989e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraft != null) { 990e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft); 991e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (mRefMessage != null) { 992e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage); 993e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 99462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 99562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mReplyFromAccount == null) { 996238aa47dbd4426e8bd1c958e68a9d9b70c9be0f7Andy Huang mReplyFromAccount = getDefaultReplyFromAccount(mAccount); 99762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 9989a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 99962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.setCurrentAccount(mReplyFromAccount); 10009a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 100162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mFromSpinner.getCount() > 1) { 1002a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // If there is only 1 account, just show that account. 1003a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // Otherwise, give the user the ability to choose which account to 100462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // send mail from / save drafts to. 100562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromStatic.setVisibility(View.GONE); 1006bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler // TODO: do we want name or address here? 1007c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromStaticText.setText(mReplyFromAccount.name); 100862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinnerWrapper.setVisibility(View.VISIBLE); 1009a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } else { 1010a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStatic.setVisibility(View.VISIBLE); 1011bb036ff794f022bba2f501e155ef9c412e0e452eTony Mantler // TODO: do we want name or address here? 1012c97ec3e157f1b2a30ebdc96ba9c6007f2f719aa6Paul Westbrook mFromStaticText.setText(mReplyFromAccount.name); 1013a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromSpinnerWrapper.setVisibility(View.GONE); 1014a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } 101546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 101646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 101762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) { 101862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (refMessage.accountUri != null) { 101962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // This must be from combined inbox. 102062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 102162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 102262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.account.uri.equals(refMessage.accountUri)) { 102362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 102462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 102562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 102662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return null; 102762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 102862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getReplyFromAccount(account, refMessage); 102962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 103062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 103162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 103262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 10339016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler * Given an account and the message we're replying to, 103462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * return who the message should be sent from. 103562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param account Account in which the message arrived. 10369016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler * @param refMessage Message to analyze for account selection 103762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @return the address from which to reply. 103862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 103962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) { 104062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // First see if we are supposed to use the default address or 104162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // the address it was sentTo. 1042326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (mCachedSettings.forceReplyFromDefault) { 104362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getDefaultReplyFromAccount(account); 104462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 104589bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira // If we aren't explicitly told which account to look for, look at 104662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // all the message recipients and find one that matches 104762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // a custom from or account. 104862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<String> allRecipients = new ArrayList<String>(); 10499016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler allRecipients.addAll(Arrays.asList(refMessage.getToAddressesUnescaped())); 10509016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler allRecipients.addAll(Arrays.asList(refMessage.getCcAddressesUnescaped())); 105162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getMatchingRecipient(account, allRecipients); 105262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 105362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 105462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 105562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 105662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Compare all the recipients of an email to the current account and all 105762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * custom addresses associated with that account. Return the match if there 105862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * is one, or the default account if there isn't. 105962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 106062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) { 106162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // Tokenize the list and place in a hashmap. 106262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount matchingReplyFrom = null; 106362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira Rfc822Token[] tokens; 106462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira HashSet<String> recipientsMap = new HashSet<String>(); 106562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (String address : sentTo) { 106662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira tokens = Rfc822Tokenizer.tokenize(address); 106762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (int i = 0; i < tokens.length; i++) { 106862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira recipientsMap.add(tokens[i].getAddress()); 106962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 107062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 107162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 107262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira int matchingAddressCount = 0; 107362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> customFroms; 10741617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang customFroms = account.getReplyFroms(); 10751617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang if (customFroms != null) { 10761617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang for (ReplyFromAccount entry : customFroms) { 10771617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang if (recipientsMap.contains(entry.address)) { 10781617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang matchingReplyFrom = entry; 10791617481de7c1f9b8dfcd25ba9828e933cf9d5490Andy Huang matchingAddressCount++; 108062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 108162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 108262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 108362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (matchingAddressCount > 1) { 108462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = getDefaultReplyFromAccount(account); 108562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 108662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return matchingReplyFrom; 108762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 108862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 1089ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static ReplyFromAccount getDefaultReplyFromAccount(final Account account) { 1090ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final ReplyFromAccount from : account.getReplyFroms()) { 109162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.isDefault) { 109262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 109362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 109462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 109579b1156803585952a4851221dc9fa9974e606433Tony Mantler return new ReplyFromAccount(account, account.uri, account.getEmailAddress(), account.name, 109679b1156803585952a4851221dc9fa9974e606433Tony Mantler account.getEmailAddress(), true, false); 109762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 109862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 1099e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) { 11008960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy String sender = msg.getFrom(); 110162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount replyFromAccount = null; 110262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 110379b1156803585952a4851221dc9fa9974e606433Tony Mantler if (TextUtils.equals(account.getEmailAddress(), sender)) { 110479b1156803585952a4851221dc9fa9974e606433Tony Mantler replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, 110579b1156803585952a4851221dc9fa9974e606433Tony Mantler mAccount.getEmailAddress(), mAccount.name, mAccount.getEmailAddress(), 110679b1156803585952a4851221dc9fa9974e606433Tony Mantler true, false); 110762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 110862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount fromAccount : replyFromAccounts) { 110979b1156803585952a4851221dc9fa9974e606433Tony Mantler if (TextUtils.equals(fromAccount.address, sender)) { 111062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = fromAccount; 111162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira break; 111262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 111362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 111462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 111562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return replyFromAccount; 111662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 111762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 111846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 1119b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.compose).setVisibility(View.VISIBLE); 1120a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 11218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 11228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 11238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 11248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 11257b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 112693b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp mPhotoAttachmentsButton = findViewById(R.id.add_photo_attachment); 1127cd0b0b950efebfc3964334067747b97e61c4f027mindyp if (mPhotoAttachmentsButton != null) { 1128cd0b0b950efebfc3964334067747b97e61c4f027mindyp mPhotoAttachmentsButton.setOnClickListener(this); 1129cd0b0b950efebfc3964334067747b97e61c4f027mindyp } 113093b079ba1d38d919b557dabcd971e7aa1e3f5cbcmindyp mVideoAttachmentsButton = findViewById(R.id.add_video_attachment); 1131cd0b0b950efebfc3964334067747b97e61c4f027mindyp if (mVideoAttachmentsButton != null) { 1132cd0b0b950efebfc3964334067747b97e61c4f027mindyp mVideoAttachmentsButton.setOnClickListener(this); 1133cd0b0b950efebfc3964334067747b97e61c4f027mindyp } 1134818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 113541500399a7ee9066319c0b07055638b07312c8acScott Kennedy mTo.setTokenizer(new Rfc822Tokenizer()); 1136818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 113741500399a7ee9066319c0b07055638b07312c8acScott Kennedy mCc.setTokenizer(new Rfc822Tokenizer()); 1138818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 113941500399a7ee9066319c0b07055638b07312c8acScott Kennedy mBcc.setTokenizer(new Rfc822Tokenizer()); 114082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 114182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 11426349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 114362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp mSubject.setOnEditorActionListener(this); 114446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 114546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 1146433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView = (EditText) findViewById(R.id.body); 11471a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 11482eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 1149eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 11505a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 1151326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1152326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 115362d3ec7f251f6f9a96a859a2702916d07f30a04amindyp @Override 115462d3ec7f251f6f9a96a859a2702916d07f30a04amindyp public boolean onEditorAction(TextView view, int action, KeyEvent keyEvent) { 115562d3ec7f251f6f9a96a859a2702916d07f30a04amindyp if (action == EditorInfo.IME_ACTION_DONE) { 115662d3ec7f251f6f9a96a859a2702916d07f30a04amindyp focusBody(); 115762d3ec7f251f6f9a96a859a2702916d07f30a04amindyp return true; 115862d3ec7f251f6f9a96a859a2702916d07f30a04amindyp } 115962d3ec7f251f6f9a96a859a2702916d07f30a04amindyp return false; 116062d3ec7f251f6f9a96a859a2702916d07f30a04amindyp } 116162d3ec7f251f6f9a96a859a2702916d07f30a04amindyp 1162e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira protected TextView getBody() { 1163e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mBodyView; 1164e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 1165e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 1166e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1167e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public Account getFromAccount() { 1168e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mReplyFromAccount != null && mReplyFromAccount.account != null ? 1169e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira mReplyFromAccount.account : mAccount; 1170e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 1171e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 1172cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira private void clearChangeListeners() { 1173cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mSubject.removeTextChangedListener(this); 1174cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBodyView.removeTextChangedListener(this); 1175cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mTo.removeTextChangedListener(mToListener); 1176cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCc.removeTextChangedListener(mCcListener); 1177cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBcc.removeTextChangedListener(mBccListener); 1178cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mFromSpinner.setOnAccountChangedListener(null); 1179cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mAttachmentsView.setAttachmentChangesListener(null); 1180cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1181cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira 118275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 118375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 118475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 118575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 11861d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp // Make sure we only add text changed listeners once! 11871d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp clearChangeListeners(); 118875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 118975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 1190cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mToListener == null) { 1191cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mToListener = new RecipientTextWatcher(mTo, this); 1192cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1193cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mTo.addTextChangedListener(mToListener); 1194cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mCcListener == null) { 1195cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCcListener = new RecipientTextWatcher(mCc, this); 1196cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1197cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mCc.addTextChangedListener(mCcListener); 1198cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira if (mBccListener == null) { 1199cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBccListener = new RecipientTextWatcher(mBcc, this); 1200cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira } 1201cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira mBcc.addTextChangedListener(mBccListener); 120275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 1203818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 120475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 120575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 1206a990a715012379451344246c5156d29938f12886Alice Yang private void initActionBar() { 1207a990a715012379451344246c5156d29938f12886Alice Yang LogUtils.d(LOG_TAG, "initializing action bar in ComposeActivity"); 1208eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 1209e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar == null) { 1210e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return; 1211e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 1212a990a715012379451344246c5156d29938f12886Alice Yang if (mComposeMode == ComposeActivity.COMPOSE) { 1213eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 1214eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 1215326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 1216eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 1217326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 1218326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 1219326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1220eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 1221eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 1222a990a715012379451344246c5156d29938f12886Alice Yang switch (mComposeMode) { 1223326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 1224eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 1225326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 1226326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 1227eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 1228326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 1229326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 1230eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 1231326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 1232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 12336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 1234fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 1235fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 1236fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 12376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 12386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 12390aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy private void initFromRefMessage(int action) { 12400aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy setFieldsFromRefMessage(action); 12411ebc2db723ed29093d724eb5da906a496ee57224Alice Yang 12421ebc2db723ed29093d724eb5da906a496ee57224Alice Yang // Check if To: address and email body needs to be prefilled based on extras. 12431ebc2db723ed29093d724eb5da906a496ee57224Alice Yang // This is used for reporting rendering feedback. 12441ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (MessageHeaderView.ENABLE_REPORT_RENDERING_PROBLEM) { 12451ebc2db723ed29093d724eb5da906a496ee57224Alice Yang Intent intent = getIntent(); 12461ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (intent.getExtras() != null) { 12471ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String toAddresses = intent.getStringExtra(EXTRA_TO); 12481ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (toAddresses != null) { 12491ebc2db723ed29093d724eb5da906a496ee57224Alice Yang addToAddresses(Arrays.asList(TextUtils.split(toAddresses, ","))); 12501ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 12511ebc2db723ed29093d724eb5da906a496ee57224Alice Yang String body = intent.getStringExtra(EXTRA_BODY); 12521ebc2db723ed29093d724eb5da906a496ee57224Alice Yang if (body != null) { 12531ebc2db723ed29093d724eb5da906a496ee57224Alice Yang setBody(body, false /* withSignature */); 12541ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 12551ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 12561ebc2db723ed29093d724eb5da906a496ee57224Alice Yang } 12571ebc2db723ed29093d724eb5da906a496ee57224Alice Yang 125896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira if (mRefMessage != null) { 125996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // CC field only gets populated when doing REPLY_ALL. 126096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // BCC never gets auto-populated, unless the user is editing 126196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // a draft with one. 126229a717e1047a2b50574e358c94a8ee8a41f377e9Mindy Pereira if (!TextUtils.isEmpty(mCc.getText()) && action == REPLY_ALL) { 126396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira mCcBccView.show(false, true, false); 126496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 126596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 126696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira updateHideOrShowCcBcc(); 126796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 126896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 12690aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy private void setFieldsFromRefMessage(int action) { 12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12750aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy initRecipientsFromRefMessage(mRefMessage, action); 1276e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 12796349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 1280c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 1281c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 1282e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromDraftMessage(Message message) { 12831f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang LogUtils.d(LOG_TAG, "Intializing draft from previous draft message: %s", message); 1284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 1285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 1286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 1287bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 1288bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 12899016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler final List<String> toAddresses = Arrays.asList(message.getToAddressesUnescaped()); 1290bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 12919016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler addCcAddresses(Arrays.asList(message.getCcAddressesUnescaped()), toAddresses); 12929016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler addBccAddresses(Arrays.asList(message.getBccAddressesUnescaped())); 12932421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (message.hasAttachments) { 12942421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira List<Attachment> attachments = message.getAttachments(); 12952421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira for (Attachment a : attachments) { 12965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(a); 12972421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 12982421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1299cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira int quotedTextIndex = message.appendRefMessageContent ? 1300002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.quotedTextOffset : -1; 1301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 1302002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence quotedText = null; 1303bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 1304752222d839d9afeb5c4665669eab81645e413495Mindy Pereira CharSequence htmlText = ""; 1305002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 1306752222d839d9afeb5c4665669eab81645e413495Mindy Pereira // Find the offset in the htmltext of the actual quoted text and strip it out. 1307752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedTextIndex = QuotedTextView.findQuotedTextIndex(message.bodyHtml); 1308752222d839d9afeb5c4665669eab81645e413495Mindy Pereira if (quotedTextIndex > -1) { 1309c59dd8270215f97d39697dae9e69976bcfe3642bmindyp htmlText = Utils.convertHtmlToPlainText(message.bodyHtml.substring(0, 1310c59dd8270215f97d39697dae9e69976bcfe3642bmindyp quotedTextIndex)); 1311752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedText = message.bodyHtml.subSequence(quotedTextIndex, 1312752222d839d9afeb5c4665669eab81645e413495Mindy Pereira message.bodyHtml.length()); 1313752222d839d9afeb5c4665669eab81645e413495Mindy Pereira } 13141a6e938c8a97092e332707a55edb5a53996edf98Mindy Pereira } else { 1315c59dd8270215f97d39697dae9e69976bcfe3642bmindyp htmlText = Utils.convertHtmlToPlainText(message.bodyHtml); 1316002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1317002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(htmlText); 1318bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 1319752222d839d9afeb5c4665669eab81645e413495Mindy Pereira final String body = message.bodyText; 1320752222d839d9afeb5c4665669eab81645e413495Mindy Pereira final CharSequence bodyText = !TextUtils.isEmpty(body) ? 1321752222d839d9afeb5c4665669eab81645e413495Mindy Pereira (quotedTextIndex > -1 ? 1322752222d839d9afeb5c4665669eab81645e413495Mindy Pereira message.bodyText.substring(0, quotedTextIndex) : message.bodyText) 1323752222d839d9afeb5c4665669eab81645e413495Mindy Pereira : ""; 1324002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 1325752222d839d9afeb5c4665669eab81645e413495Mindy Pereira quotedText = !TextUtils.isEmpty(body) ? message.bodyText.substring(quotedTextIndex) 1326752222d839d9afeb5c4665669eab81645e413495Mindy Pereira : null; 1327002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1328002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(bodyText); 1329002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1330002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1 && quotedText != null) { 13313971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward); 1332bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1333bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1334bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 13358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 13368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 13378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 13388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 13398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 13408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 13418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 13428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 13438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 1344746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein * @return {@code true} if the activity should not call {@link #finishSetup}. 13458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 1346746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein public boolean initFromExtras(Intent intent) { 13478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 13488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 13498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 13508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 13518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 13528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 13538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 13540b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira if (!mAccount.composeIntentUri.equals(dataUri)) { 13558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 13568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 13578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 1358dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(toText, ","))); 13598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 13658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 13668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 13678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 13698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 13708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 13718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 13738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 13748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 13758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 13788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 13798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 13808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 13838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 13848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 13858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 1386dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(value, ","))); 13878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 1388dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null); 13898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 1390dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addBccAddresses(Arrays.asList(TextUtils.split(value, ","))); 13918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 13928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 13938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 13948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 1395bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } else if (EXTRA_QUOTED_TEXT.equals(extra)) { 1396bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein initQuotedText(value, true /* shouldQuoteText */); 13978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 13998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 14018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 14028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 14038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 14048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 14058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 14068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1407bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein 1408bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein // TODO - support EXTRA_HTML_TEXT 14098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1410746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein 1411746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein mExtraValues = intent.getParcelableExtra(EXTRA_VALUES); 1412746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein if (mExtraValues != null) { 1413746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein LogUtils.d(LOG_TAG, "Launched with extra values: %s", mExtraValues.toString()); 1414746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein initExtraValues(mExtraValues); 1415746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein return true; 1416746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein } 1417746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein 1418746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein return false; 1419746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein } 1420746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein 1421746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein protected void initExtraValues(ContentValues extraValues) { 1422746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein // DO NOTHING - Gmail will override 1423e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 1424e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 1425bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein 14268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 14278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 1428a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // TODO: handle the case where there are spaces in the display name as 1429a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>" 1430a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // as they could be encoded ambiguously. 14318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 14328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 14338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 1434a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira try { 14357dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee return URLDecoder.decode(replacePlus(s), UTF8_ENCODING_NAME); 1436a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } catch (IllegalArgumentException e) { 1437a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 1438a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s); 1439a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } else { 1440a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 1441a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 1442a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira return null; 1443a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 14448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 14468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 14477dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * Replaces all occurrences of '+' with "%2B", to prevent URLDecode.decode from 14487dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * changing '+' into ' ' 14497dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * 14507dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * @param toReplace Input string 14517dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee * @return The string with all "+" characters replaced with "%2B" 14527dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee */ 14533b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy private static String replacePlus(String toReplace) { 14547dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee return toReplace.replace("+", "%2B"); 14557dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee } 14567dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee 14577dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee /** 14588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 14598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 14608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 14618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 14628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 14638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 14648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 14658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 14668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 14678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 14688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 14698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 14708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 14718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 14728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 14738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 14748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1475a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (!TextUtils.isEmpty(to)) { 1476a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira addToAddresses(Arrays.asList(TextUtils.split(to, ","))); 1477a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 14788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 14798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 14808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 14818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 14828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 14838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 14858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 14868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 14878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 14888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 14898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 14908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 14918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 14928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 14938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 14948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 14958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 14968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 14978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 14987dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee mSubject.setText(URLDecoder.decode(replacePlus(subject.get(0)), 14997dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee UTF8_ENCODING_NAME)); 15008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 15018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 15028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 15038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 15048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 15058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 15068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 15078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 15088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 15097dd05b1b54673fe526ea35aa44e37827e8d38aa5Yorke Lee setBody(URLDecoder.decode(replacePlus(body.get(0)), UTF8_ENCODING_NAME), 15108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 15118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 15128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 15138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 15148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 15158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 15168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1517bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira @VisibleForTesting 1518bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira protected void initAttachments(Message refMessage) { 1519434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei addAttachments(refMessage.getAttachments()); 1520434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1521434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei 1522434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei public long addAttachments(List<Attachment> attachments) { 1523434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei long size = 0; 1524434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei AttachmentFailureException error = null; 1525434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei for (Attachment a : attachments) { 1526434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei try { 1527434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei size += mAttachmentsView.addAttachment(mAccount, a); 1528434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } catch (AttachmentFailureException e) { 1529434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei error = e; 1530434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1531434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 1532434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei if (error != null) { 1533434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei LogUtils.e(LOG_TAG, error, "Error adding attachment"); 1534434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei if (attachments.size() > 1) { 1535434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(R.string.too_large_to_attach_multiple); 1536434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } else { 1537434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(error.getErrorRes()); 1538434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei } 15393cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 1540434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei return size; 15413cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 15423cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira 15433cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira /** 15443cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * When an attachment is too large to be added to a message, show a toast. 15453cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * This method also updates the position of the toast so that it is shown 15463cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira * clearly above they keyboard if it happens to be open. 15473cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira */ 1548434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei private void showAttachmentTooBigToast(int errorRes) { 1549434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei String maxSize = AttachmentUtils.convertToHumanReadableSize( 1550434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), mAccount.settings.getMaxAttachmentSize()); 1551434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getString(errorRes, maxSize)); 15523cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira } 15533cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira 1554434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei private void showErrorToast(String message) { 1555434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei Toast t = Toast.makeText(this, message, Toast.LENGTH_LONG); 1556434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei t.setText(message); 15573cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira t.setGravity(Gravity.CENTER_HORIZONTAL, 0, 15583cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira getResources().getDimensionPixelSize(R.dimen.attachment_toast_yoffset)); 15593cd4f40dab2c0810cb5ecd77256abf022863b2b5Mindy Pereira t.show(); 1560eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1561eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1562f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 156303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook Bundle extras = intent.getExtras(); 156403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook if (extras == null) { 156503ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook extras = Bundle.EMPTY; 156603ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook } 1567f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 1568f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 1569f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 1570f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 1571f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 1572f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 1573f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 1574f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1575f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 1576e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang final Attachment a = mAttachmentsView.generateLocalAttachment(uri); 1577e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang size = mAttachmentsView.addAttachment(mAccount, a); 1578e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 1579e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent("send_intent_attachment", 1580e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Utils.normalizeMimeType(a.getContentType()), null, size); 1581e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 1582f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1583f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1584434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1585f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1586f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1587f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1588f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 15899a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp if (extras.containsKey(Intent.EXTRA_STREAM)) { 15909a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp if (Intent.ACTION_SEND_MULTIPLE.equals(action)) { 15919a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp ArrayList<Parcelable> uris = extras 15929a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp .getParcelableArrayList(Intent.EXTRA_STREAM); 15939a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp ArrayList<Attachment> attachments = new ArrayList<Attachment>(); 15949a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp for (Parcelable uri : uris) { 15959a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp try { 1596e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang final Attachment a = mAttachmentsView.generateLocalAttachment( 1597e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang (Uri) uri); 1598e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang attachments.add(a); 1599e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 1600e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent("send_intent_attachment", 1601e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Utils.normalizeMimeType(a.getContentType()), null, a.size); 1602e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 16039a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } catch (AttachmentFailureException e) { 16049a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp LogUtils.e(LOG_TAG, e, "Error adding attachment"); 16059a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp String maxSize = AttachmentUtils.convertToHumanReadableSize( 16069a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp getApplicationContext(), 16079a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp mAccount.settings.getMaxAttachmentSize()); 16089a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp showErrorToast(getString 16099a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp (R.string.generic_attachment_problem, maxSize)); 16109a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } 16119a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } 16129a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp totalSize += addAttachments(attachments); 16139a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp } else { 16149a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 16159a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp long size = 0; 1616f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 1617e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang final Attachment a = mAttachmentsView.generateLocalAttachment(uri); 1618e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang size = mAttachmentsView.addAttachment(mAccount, a); 1619e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 1620e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent("send_intent_attachment", 1621e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Utils.normalizeMimeType(a.getContentType()), null, size); 1622e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 1623f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1624f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 16259a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp showAttachmentTooBigToast(e.getErrorRes()); 1626f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 16279a9e8d698ce11fb5fa8e7afecf587147f1a4e02amindyp totalSize += size; 1628f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1629f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1630f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1631f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 1632f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 1633f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 1634e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 1635e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent("send_intent_with_attachments", 1636e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Integer.toString(getAttachments().size()), null, totalSize); 1637f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1638f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1639f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1640f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1641746d8613b86533ceb9724edccb9815ad8af710baAndrew Sapperstein protected void initQuotedText(CharSequence quotedText, boolean shouldQuoteText) { 1642bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein mQuotedTextView.setQuotedTextFromHtml(quotedText, shouldQuoteText); 1643bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein mShowQuotedText = true; 1644bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } 1645f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1646e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initQuotedTextFromRefMessage(Message refMessage, int action) { 1647e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) { 16489932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 16499932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 165046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 165146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 165246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 1653ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1654326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean ccVisible = mCcBccView.isCcVisible(); 1655326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean bccVisible = mCcBccView.isBccVisible(); 1656ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1657326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (!ccVisible || !bccVisible) { 1658ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 1659326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label 1660ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1661ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1662cd0b0b950efebfc3964334067747b97e61c4f027mindyp mCcBccButton.setVisibility(View.INVISIBLE); 1663ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1664ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 166546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 166646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1667a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira private void showCcBcc(Bundle state) { 1668326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (state != null && state.containsKey(EXTRA_SHOW_CC)) { 1669326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showCc = state.getBoolean(EXTRA_SHOW_CC); 1670326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC); 1671326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (showCc || showBcc) { 1672326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccView.show(false, showCc, showBcc); 1673326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1674326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1675326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1676326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira 1677013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 1678013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 1679013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 1680013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 1681013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 16822421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null); 16832421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 16842421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira 16855c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Uri contentUri) { 16865c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang if (contentUri == null) { 16872421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira return; 16882421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1689013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 16905c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri)); 16915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } catch (AttachmentFailureException e) { 16925c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1693434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showErrorToast(getResources().getString( 1694434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei e.getErrorRes(), 1695434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei AttachmentUtils.convertToHumanReadableSize( 1696434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei getApplicationContext(), mAccount.settings.getMaxAttachmentSize()))); 16975c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 16985c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 16995c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang 17005c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Attachment attachment) { 17015c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang try { 1702434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei long size = mAttachmentsView.addAttachment(mAccount, attachment); 17039932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 17049932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 17059932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 1706013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 17079932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 17089932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1709434f294a3ae17a4f76342af38d6376f672a5d9edMark Wei showAttachmentTooBigToast(e.getErrorRes()); 1710013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1711013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1712013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 17130aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy void initRecipientsFromRefMessage(Message refMessage, int action) { 17144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 17154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 17164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 17174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 1718ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy initReplyRecipients(refMessage, action); 17194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 17216d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook // TODO: This should be private. This method shouldn't be used by ComposeActivityTests, as 17226d2442ba4417717b2a19714b0ac28c7265872ba3Paul Westbrook // it doesn't setup the state of the activity correctly 1723818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 1724ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy void initReplyRecipients(final Message refMessage, final int action) { 17259016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler String[] sentToAddresses = refMessage.getToAddressesUnescaped(); 1726a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 172789de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler final String[] replyToAddresses = refMessage.getReplyToAddressesUnescaped(); 172889de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler String replyToAddress = replyToAddresses.length > 0 ? replyToAddresses[0] : null; 172989de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler final String[] fromAddresses = refMessage.getFromAddressesUnescaped(); 173089de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler final String fromAddress = fromAddresses.length > 0 ? fromAddresses[0] : null; 173189de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler 173265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // If there is no reply to address, the reply to address is the sender. 173389de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler if (TextUtils.isEmpty(replyToAddress)) { 173489de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler replyToAddress = fromAddress; 173565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp } 17364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 17374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 17384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 17394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 1740a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 1741a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 174289de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses); 1743a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 1744a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 17454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 174689de9eb1933bb2df287b74a93f6de5b1d19895aeTony Mantler toAddresses = initToRecipients(fromAddress, replyToAddress, sentToAddresses); 1747154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 1748ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy addRecipients(ccAddresses, sentToAddresses); 17499016a5e827ae7baff9199811ecc8a9de9690b838Tony Mantler addRecipients(ccAddresses, refMessage.getCcAddressesUnescaped()); 17504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 17514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 17544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 17554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 17564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 17584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 17598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 17608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 17614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1763bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 1764bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 1765bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1766bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 17674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 17684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 17694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 17704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 17714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 17728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 17738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 17748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 17758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 17764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 17774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17784a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 17808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 17818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 17828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 17838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 17848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 17858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 17868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 17878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 17888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 17898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 17908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 17914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 17934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1794ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static HashSet<String> convertToHashSet(final List<Rfc822Token[]> list) { 1795ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final HashSet<String> hash = new HashSet<String>(); 1796ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final Rfc822Token[] tokens : list) { 17974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 17984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 17994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 18024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 18044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 18054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 18064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 18074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 18084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 18094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 18104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 18124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 18144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 18154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 18164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 18174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 18184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1821ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static void addAddressToList(final String address, final RecipientEditTextView list) { 18224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 18234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 18244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1825ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 18264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 18274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 18284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 18294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 18324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 1833ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy protected Collection<String> initToRecipients(final String fullSenderAddress, 1834ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final String replyToAddress, final String[] inToAddresses) { 18354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 18364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 18374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 18384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 18394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 18404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 184165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp if (!TextUtils.isEmpty(replyToAddress) && !recipientMatchesThisAccount(replyToAddress)) { 18423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 18434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 184465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // In this case, the user is replying to a message in which their 184565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // current account or one of their custom from addresses is the only 184665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // recipient and they sent the original message. 184765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp if (inToAddresses.length == 1 && recipientMatchesThisAccount(fullSenderAddress) 184865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp && recipientMatchesThisAccount(inToAddresses[0])) { 184965b06f52e5b6336493388923be88bdd2ded4e1d1mindyp toAddresses.add(inToAddresses[0]); 185065b06f52e5b6336493388923be88bdd2ded4e1d1mindyp return toAddresses; 185165b06f52e5b6336493388923be88bdd2ded4e1d1mindyp } 185265b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // This happens if the user replies to a message they originally 185365b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // wrote. In this case, "reply" really means "re-send," so we 185465b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // target the original recipients. This works as expected even 185565b06f52e5b6336493388923be88bdd2ded4e1d1mindyp // if the user sent the original message to themselves. 185665b06f52e5b6336493388923be88bdd2ded4e1d1mindyp for (String address : inToAddresses) { 185765b06f52e5b6336493388923be88bdd2ded4e1d1mindyp if (!recipientMatchesThisAccount(address)) { 185865b06f52e5b6336493388923be88bdd2ded4e1d1mindyp toAddresses.add(address); 1859fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp } 18601469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 18614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 18634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1865ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private void addRecipients(final Set<String> recipients, final String[] addresses) { 1866ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final String email : addresses) { 1867cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira // Do not add this account, or any of its custom from addresses, to 1868cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira // the list of recipients. 18694a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 18705ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp if (!recipientMatchesThisAccount(recipientAddress)) { 18714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 18724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 18734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 187446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 187546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1876cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira /** 1877cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * A recipient matches this account if it has the same address as the 1878cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * currently selected account OR one of the custom from addresses associated 1879cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * with the currently selected account. 1880cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @param recipientAddress address we are comparing with the currently selected account 1881cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira * @return 1882cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira */ 18835ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp protected boolean recipientMatchesThisAccount(String recipientAddress) { 18845ee5d69dc7ddbef52c6c62947757b3d86ac89f23mindyp return ReplyFromAccount.matchesAccountOrCustomFrom(mAccount, recipientAddress, 1885fe8557b7a3aca8c41d85edbc9a094d96aacb08e5mindyp mAccount.getReplyFroms()); 1886cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira } 1887cecc54a913a665af3556f3fcc11cfae4d54cb3beMindy Pereira 1888bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein /** 1889bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein * Returns a formatted subject string with the appropriate prefix for the action type. 1890bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein * E.g., "FWD: " is prepended if action is {@link ComposeActivity#FORWARD}. 1891bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein */ 1892bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein public static String buildFormattedSubject(Resources res, String subject, int action) { 189346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 189446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 189546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 189646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 189746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 1898bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein prefix = res.getString(R.string.forward_subject_label); 189946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 1900bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein prefix = res.getString(R.string.reply_subject_label); 190146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 190246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 190346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 1904c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira if (!TextUtils.isEmpty(subject) 1905c7a36999abb396ac965a981e0a3f658b537213acMindy Pereira && subject.toLowerCase().startsWith(prefix.toLowerCase())) { 190646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 190746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 1908bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein correctedSubject = String.format( 1909bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein res.getString(R.string.formatted_subject), prefix, subject); 191046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 1911bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein 1912bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein return correctedSubject; 1913bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein } 1914bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein 1915bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein private void setSubject(Message refMessage, int action) { 1916bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein mSubject.setText(buildFormattedSubject(getResources(), refMessage.subject, action)); 191746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 191846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1919818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 1920818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 1921818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 1922818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 1923eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1924eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1925818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 1926679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 192782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 192879b1156803585952a4851221dc9fa9974e606433Tony Mantler final String accountName = mAccount.getEmailAddress(); 192933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 193033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 193179b1156803585952a4851221dc9fa9974e606433Tony Mantler if (offset > 0) { 193279b1156803585952a4851221dc9fa9974e606433Tony Mantler account = account.substring(offset); 1933c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 193482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 1935c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 193682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 19378e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 19388e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 19398e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 19408e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 19412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final int id = v.getId(); 19422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (id == R.id.add_cc_bcc) { 19432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Verify that cc/ bcc aren't showing. 19442b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Animate in cc/bcc. 19452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy showCcBccViews(); 19462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_photo_attachment) { 19472b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_PHOTO); 19482b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_video_attachment) { 19492b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_VIDEO); 19508e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 19518e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1952b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1953b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1954b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 19555b8799a200e53e1eb66963e716b911b35bffecafTony Mantler final boolean superCreated = super.onCreateOptionsMenu(menu); 1956b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Don't render any menu items when there are no accounts. 1957b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (mAccounts == null || mAccounts.length == 0) { 19585b8799a200e53e1eb66963e716b911b35bffecafTony Mantler return superCreated; 1959b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 1960b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1961b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 19621d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp 19631d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp /* 19641d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * Start save in the correct enabled state. 19651d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * 1) If a user launches compose from within gmail, save is disabled 19661d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * until they add something, at which point, save is enabled, auto save 19671d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * on exit; if the user empties everything, save is disabled, exiting does not 19681d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * auto-save 19691d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * 2) if a user replies/ reply all/ forwards from within gmail, save is 19701d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * disabled until they change something, at which point, save is 19711d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * enabled, auto save on exit; if the user empties everything, save is 19721d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * disabled, exiting does not auto-save. 19731d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * 3) If a user launches compose from another application and something 19741d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * gets populated (attachments, recipients, body, subject, etc), save is 19751d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * enabled, auto save on exit; if the user empties everything, save is 19761d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp * disabled, exiting does not auto-save 19771d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp */ 197882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 19791d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp String action = getIntent() != null ? getIntent().getAction() : null; 19809f855d667e34fbf0d330845225c26956e540b819Andy Huang enableSave(mInnerSavedState != null ? 19819f855d667e34fbf0d330845225c26956e540b819Andy Huang mInnerSavedState.getBoolean(EXTRA_SAVE_ENABLED) 19821d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp : (Intent.ACTION_SEND.equals(action) 19831d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp || Intent.ACTION_SEND_MULTIPLE.equals(action) 19841d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp || Intent.ACTION_SENDTO.equals(action) 19851d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp || shouldSave())); 19861d7e9145fa4f490ba87ade0ed70ce0fa1f33be81mindyp 198782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 19883ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem helpItem = menu.findItem(R.id.help_info_menu_item); 19893ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item); 19903ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (helpItem != null) { 19913ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira helpItem.setVisible(mAccount != null 19923ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT)); 19933ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 19943ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (sendFeedbackItem != null) { 19953ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira sendFeedbackItem.setVisible(mAccount != null 19963ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK)); 19973ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 1998b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1999b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 2000b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 2001b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 2002ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 2003ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 2004818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 2005ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 2006ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 2007ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 2008ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 2009ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 2010ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 2011ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 2012ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 2013ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 2014ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2015ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2016ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 2017ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2018ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 2019ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 2020b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 20212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final int id = item.getItemId(); 2022dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang 2023dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang Analytics.getInstance().sendMenuItemEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, id, null, 0); 2024dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang 202575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 20262b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (id == R.id.add_photo_attachment) { 20272b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_PHOTO); 20282b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_video_attachment) { 20292b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doAttach(MIME_TYPE_VIDEO); 20302b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.add_cc_bcc) { 20312b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy showCcBccViews(); 20322b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.save) { 20332b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doSave(true); 20342b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.send) { 20352b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doSend(); 20362b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.discard) { 20372b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy doDiscard(); 20382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.settings) { 20392b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.showSettings(this, mAccount); 20402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == android.R.id.home) { 20412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy onAppUpPressed(); 20422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.help_info_menu_item) { 20432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.showHelp(this, mAccount, getString(R.string.compose_help_context)); 20442b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (id == R.id.feedback_menu_item) { 20452b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy Utils.sendFeedback(this, mAccount, false); 20462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else { 20472b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy handled = false; 2048b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 2049b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 2050b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 2051326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2052b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira @Override 2053b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira public void onBackPressed() { 2054b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // If we are showing the wait fragment, just exit. 2055b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (getWaitFragment() != null) { 2056b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 2057b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 2058b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira super.onBackPressed(); 2059b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2060b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 2061b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 20621672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal /** 20631672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal * Carries out the "up" action in the action bar. 20641672ff8ed6741df5c245e55f7a4e847f6ccb8c52Vikram Aggarwal */ 2065daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private void onAppUpPressed() { 2066daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (mLaunchedFromEmail) { 2067daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // If this was started from Gmail, simply treat app up as the system back button, so 2068daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // that the last view is restored. 2069daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook onBackPressed(); 2070daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook return; 2071daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 2072daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 2073daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Fire the main activity to ensure it launches the "top" screen of mail. 2074daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Since the main Activity is singleTask, it should revive that task if it was already 2075daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // started. 20760c3c2058f75487713c64634c7f08025fd78ba012Vikram Aggarwal final Intent mailIntent = Utils.createViewInboxIntent(mAccount); 2077daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 2078daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook Intent.FLAG_ACTIVITY_TASK_ON_HOME); 2079daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook startActivity(mailIntent); 2080daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook finish(); 2081daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 2082daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 208333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 2084dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei sendOrSaveWithSanityChecks(false, true, false, false); 2085dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang logSendOrSave(false /* save */); 2086dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang mPerformedSendOrDiscard = true; 208733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 208833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 208948e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira private void doSave(boolean showToast) { 2090dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei sendOrSaveWithSanityChecks(true, showToast, false, false); 209148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira } 209248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira 2093e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2094e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public interface SendOrSaveCallback { 209582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 20967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 20977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 209882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 209982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 210082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2101e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2102e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveTask implements Runnable { 210382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 210482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 2105e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveCallback mSendOrSaveCallback; 2106e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2107e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveMessage mSendOrSaveMessage; 210844a6339dd80f4b5b9e5d54567021698d92467c5emindyp private ReplyFromAccount mExistingDraftAccount; 210982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 211082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 211144a6339dd80f4b5b9e5d54567021698d92467c5emindyp SendOrSaveCallback callback, ReplyFromAccount draftAccount) { 211282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 211382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 211482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 211544a6339dd80f4b5b9e5d54567021698d92467c5emindyp mExistingDraftAccount = draftAccount; 211682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 211782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 211882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 211982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 21207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 212182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 212292551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount; 21237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 21247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 212582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 212682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 212782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 212844a6339dd80f4b5b9e5d54567021698d92467c5emindyp if (mExistingDraftAccount != null 212944a6339dd80f4b5b9e5d54567021698d92467c5emindyp && !selectedAccount.account.uri.equals(mExistingDraftAccount.account.uri)) { 213082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 213182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 213282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 213382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 2134febd226e871263aeb21d436bee81eb2f7dec3d03mindyp if (mExistingDraftAccount.account.expungeMessageUri != null) { 2135febd226e871263aeb21d436bee81eb2f7dec3d03mindyp new ContentProviderTask.UpdateTask() 2136febd226e871263aeb21d436bee81eb2f7dec3d03mindyp .run(resolver, mExistingDraftAccount.account.expungeMessageUri, 2137febd226e871263aeb21d436bee81eb2f7dec3d03mindyp values, null, null); 2138cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 2139cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 2140eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 214182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 214282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 214382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 214482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 214582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 214682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 2147ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy sendOrSaveMessage(messageIdToSave, sendOrSaveMessage, selectedAccount); 214872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 214972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook if (!sendOrSaveMessage.mSave) { 21509f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler incrementRecipientsTimesContacted(mContext, 215172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 21529f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler incrementRecipientsTimesContacted(mContext, 215372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 21549f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler incrementRecipientsTimesContacted(mContext, 215572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 215672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 215772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 215872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 215972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 21609f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler private static void incrementRecipientsTimesContacted(final Context context, 21619f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler final String addressString) { 21629f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler if (TextUtils.isEmpty(addressString)) { 21639f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler return; 21649f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler } 21659f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressString); 21669f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler final ArrayList<String> recipients = new ArrayList<String>(tokens.length); 21679f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler for (int i = 0; i < tokens.length;i++) { 21689f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler recipients.add(tokens[i].getAddress()); 21699f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler } 21709f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler final DataUsageStatUpdater statsUpdater = new DataUsageStatUpdater(context); 21719f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler statsUpdater.updateWithAddress(recipients); 21729f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler } 21739f32423b2e1f7ef6747eb1a27f3faa15f5a3db1cTony Mantler 217472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook /** 217572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * Send or Save a message. 217672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook */ 2177ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private void sendOrSaveMessage(final long messageIdToSave, 2178ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final SendOrSaveMessage sendOrSaveMessage, final ReplyFromAccount selectedAccount) { 217972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final ContentResolver resolver = mContext.getContentResolver(); 218072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final boolean updateExistingMessage = messageIdToSave != UIProvider.INVALID_MESSAGE_ID; 218172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 218272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final String accountMethod = sendOrSaveMessage.mSave ? 218372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.AccountCallMethods.SAVE_MESSAGE : 218472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook UIProvider.AccountCallMethods.SEND_MESSAGE; 218572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 21863c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook try { 21873c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (updateExistingMessage) { 21883c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 21893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 2190013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook callAccountSendSaveMethod(resolver, 21913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook selectedAccount.account, accountMethod, sendOrSaveMessage); 219272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else { 2193013a23c75cf8a71c51ad1580aa84f2a8e06b6761Paul Westbrook Uri messageUri = null; 21943c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle result = callAccountSendSaveMethod(resolver, 21953c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook selectedAccount.account, accountMethod, sendOrSaveMessage); 21963c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (result != null) { 21973c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // If a non-null value was returned, then the provider handled the call 21983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // method 21993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook messageUri = result.getParcelable(UIProvider.MessageColumns.URI); 22003c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22013c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (sendOrSaveMessage.mSave && messageUri != null) { 22023c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Cursor messageCursor = resolver.query(messageUri, 22033c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook UIProvider.MESSAGE_PROJECTION, null, null, null); 22043c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (messageCursor != null) { 22053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook try { 22063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (messageCursor.moveToFirst()) { 22073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // Broadcast notification that a new message has 22083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // been allocated 22093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 22103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook new Message(messageCursor)); 22113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } finally { 22133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook messageCursor.close(); 22143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22153c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22163c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 221772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 22183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } finally { 22193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // Close any opened file descriptors 22203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook closeOpenedAttachmentFds(sendOrSaveMessage); 22213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 2224ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static void closeOpenedAttachmentFds(final SendOrSaveMessage sendOrSaveMessage) { 22253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle openedFds = sendOrSaveMessage.attachmentFds(); 22263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (openedFds != null) { 22273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Set<String> keys = openedFds.keySet(); 2228ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final String key : keys) { 22293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final ParcelFileDescriptor fd = openedFds.getParcelable(key); 22303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (fd != null) { 2231ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 22323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook fd.close(); 22333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } catch (IOException e) { 22343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // Do nothing 2235ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 22367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 22377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 224172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook /** 2242bc5e0dcf723918eb986d733ef42d64bcf2ec4ed5Andrew Sapperstein * Use the {@link ContentResolver#call} method to send or save the message. 224372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * 224472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook * If this was successful, this method will return an non-null Bundle instance 224572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook */ 2246ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static Bundle callAccountSendSaveMethod(final ContentResolver resolver, 2247ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final Account account, final String method, 2248ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final SendOrSaveMessage sendOrSaveMessage) { 224972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook // Copy all of the values from the content values to the bundle 225072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final Bundle methodExtras = new Bundle(sendOrSaveMessage.mValues.size()); 225172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final Set<Entry<String, Object>> valueSet = sendOrSaveMessage.mValues.valueSet(); 225272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 225372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook for (Entry<String, Object> entry : valueSet) { 225472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final Object entryValue = entry.getValue(); 225572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook final String key = entry.getKey(); 225672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook if (entryValue instanceof String) { 225772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putString(key, (String)entryValue); 225872e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else if (entryValue instanceof Boolean) { 225972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putBoolean(key, (Boolean)entryValue); 226072e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else if (entryValue instanceof Integer) { 226172e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putInt(key, (Integer)entryValue); 226272e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else if (entryValue instanceof Long) { 226372e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook methodExtras.putLong(key, (Long)entryValue); 226472e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } else { 226572e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook LogUtils.wtf(LOG_TAG, "Unexpected object type: %s", 226672e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook entryValue.getClass().getName()); 226772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook } 226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 226972e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook 22703c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook // If the SendOrSaveMessage has some opened fds, add them to the bundle 22713c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle fdMap = sendOrSaveMessage.attachmentFds(); 22723c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (fdMap != null) { 22733c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook methodExtras.putParcelable( 22743c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP, fdMap); 22753c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 22763c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 227772e2ea860f66f496537e37ebc0ddd2c670d4c651Paul Westbrook return resolver.call(account.uri, method, account.uri.toString(), methodExtras); 227882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 227982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 228082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2281e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2282e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveMessage { 228392551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount mAccount; 228482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 22853ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 2286e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 2287e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final boolean mSave; 228882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 22893c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook private final Bundle mAttachmentFds; 229082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 22913c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook public SendOrSaveMessage(Context context, ReplyFromAccount account, ContentValues values, 22923c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook String refMessageId, List<Attachment> attachments, boolean save) { 229382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 229482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 229582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 229682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 229782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 22983c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 22993c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook mAttachmentFds = initializeAttachmentFds(context, attachments); 230082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 230182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 230282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 230382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 230482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 23053c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23063c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook Bundle attachmentFds() { 23073c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook return mAttachmentFds; 23083c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 23093c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23103c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook /** 23113c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook * Opens {@link ParcelFileDescriptor} for each of the attachments. This method must be 23123c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook * called before the ComposeActivity finishes. 23133c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook * Note: The caller is responsible for closing these file descriptors. 23143c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook */ 2315ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy private static Bundle initializeAttachmentFds(final Context context, 2316ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final List<Attachment> attachments) { 23173c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (attachments == null || attachments.size() == 0) { 23183c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook return null; 23193c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 23203c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23213c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final Bundle result = new Bundle(attachments.size()); 23223c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook final ContentResolver resolver = context.getContentResolver(); 23233c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23243c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook for (Attachment attachment : attachments) { 23253c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (attachment == null || Utils.isEmpty(attachment.contentUri)) { 23263c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook continue; 23273c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 23283c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23293c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook ParcelFileDescriptor fileDescriptor; 23303c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook try { 23313c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook fileDescriptor = resolver.openFileDescriptor(attachment.contentUri, "r"); 23323c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } catch (FileNotFoundException e) { 23333c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook LogUtils.e(LOG_TAG, e, "Exception attempting to open attachment"); 23343c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook fileDescriptor = null; 2335c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook } catch (SecurityException e) { 2336c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // We have encountered a security exception when attempting to open the file 2337c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // specified by the content uri. If the attachment has been cached, this 2338c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // isn't a problem, as even through the original permission may have been 2339c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // revoked, we have cached the file. This will happen when saving/sending 2340c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // a previously saved draft. 2341c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // TODO(markwei): Expose whether the attachment has been cached through the 2342c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // attachment object. This would allow us to limit when the log is made, as 2343c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // if the attachment has been cached, this really isn't an error 2344c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook LogUtils.e(LOG_TAG, e, "Security Exception attempting to open attachment"); 2345c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // Just set the file descriptor to null, as the underlying provider needs 2346c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook // to handle the file descriptor not being set. 2347c537fd4729cb7545d09245bdaad033e676f29396Paul Westbrook fileDescriptor = null; 23483c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 23493c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23503c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook if (fileDescriptor != null) { 23513c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook result.putParcelable(attachment.contentUri.toString(), fileDescriptor); 23523c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 23533c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 23543c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook 23553c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook return result; 23563c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook } 235782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 235882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 235982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 236082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 236182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 236282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 236382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 236482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 236582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 236682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 236782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 236882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 236982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 237082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 237182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 237282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 237382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 237482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 237582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 237682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 237782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 237882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 237982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 238082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 238182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 238282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 238382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 238482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 238582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 238682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 238782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 238882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 238982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 239082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 239182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 239282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 239382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 239482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 239582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 239682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 239782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 2398ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy public void checkInvalidEmails(final String[] to, final List<String> wrongEmailsOut) { 2399e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira if (mValidator == null) { 2400e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira return; 2401e5f20bf1c293497625b0f2865302e6712a854959Mindy Pereira } 2402ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy for (final String email : to) { 240382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 240482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 240582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 240682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 240782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 240882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 24092558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static class RecipientErrorDialogFragment extends DialogFragment { 2410f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook // Public no-args constructor needed for fragment re-instantiation 2411f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook public RecipientErrorDialogFragment() {} 2412f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook 24132558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static RecipientErrorDialogFragment newInstance(final String message) { 24142558b509117872e539a6eaeb72aa63425529d50bTony Mantler final RecipientErrorDialogFragment frag = new RecipientErrorDialogFragment(); 24152558b509117872e539a6eaeb72aa63425529d50bTony Mantler final Bundle args = new Bundle(1); 24162558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putString("message", message); 24172558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.setArguments(args); 24182558b509117872e539a6eaeb72aa63425529d50bTony Mantler return frag; 24192558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24202558b509117872e539a6eaeb72aa63425529d50bTony Mantler 24212558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 24222558b509117872e539a6eaeb72aa63425529d50bTony Mantler public Dialog onCreateDialog(Bundle savedInstanceState) { 24232558b509117872e539a6eaeb72aa63425529d50bTony Mantler final String message = getArguments().getString("message"); 24242558b509117872e539a6eaeb72aa63425529d50bTony Mantler return new AlertDialog.Builder(getActivity()).setMessage(message).setTitle( 24252558b509117872e539a6eaeb72aa63425529d50bTony Mantler R.string.recipient_error_dialog_title) 24262558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setIconAttribute(android.R.attr.alertDialogIcon) 24272558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setPositiveButton( 24282558b509117872e539a6eaeb72aa63425529d50bTony Mantler R.string.ok, new Dialog.OnClickListener() { 24292558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 24302558b509117872e539a6eaeb72aa63425529d50bTony Mantler public void onClick(DialogInterface dialog, int which) { 24312558b509117872e539a6eaeb72aa63425529d50bTony Mantler ((ComposeActivity)getActivity()).finishRecipientErrorDialog(); 24322558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24332558b509117872e539a6eaeb72aa63425529d50bTony Mantler }).create(); 24342558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24352558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24362558b509117872e539a6eaeb72aa63425529d50bTony Mantler 24372558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void finishRecipientErrorDialog() { 24382558b509117872e539a6eaeb72aa63425529d50bTony Mantler // after the user dismisses the recipient error 24392558b509117872e539a6eaeb72aa63425529d50bTony Mantler // dialog we want to make sure to refocus the 24402558b509117872e539a6eaeb72aa63425529d50bTony Mantler // recipient to field so they can fix the issue 24412558b509117872e539a6eaeb72aa63425529d50bTony Mantler // easily 24422558b509117872e539a6eaeb72aa63425529d50bTony Mantler if (mTo != null) { 24432558b509117872e539a6eaeb72aa63425529d50bTony Mantler mTo.requestFocus(); 24442558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24452558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 24462558b509117872e539a6eaeb72aa63425529d50bTony Mantler 244782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 244882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 244982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 245082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 24512558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void showRecipientErrorDialog(final String message) { 24522558b509117872e539a6eaeb72aa63425529d50bTony Mantler final DialogFragment frag = RecipientErrorDialogFragment.newInstance(message); 24532558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.show(getFragmentManager(), "recipient error"); 245482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 245582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 245682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 245782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 245882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 245982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 2460eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 246182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 246282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 246382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 246482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 246582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 246682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 246782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 246882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 246982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 24707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 247182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 247282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 247382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 247482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 2475a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira // AND there is actually something in the draft to save. 2476d47877e3860ea4249eddb3f6efefbc6cd39f2320Andy Huang return (mTextChanged || mAttachmentsChanged || mReplyFromChanged) 2477a214833a75ba2b27cdd166ceee9a2529b13a17c4Mindy Pereira && !isBlank(); 247882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 247982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 248082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 248182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 2482bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 248382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 248482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 248582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 2486a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang // Need to check for null since isBlank() can be called from onPause() 2487a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang // before findViews() is called 2488a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang if (mSubject == null || mBodyView == null || mTo == null || mCc == null || 2489a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang mAttachmentsView == null) { 2490a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang LogUtils.w(LOG_TAG, "null views in isBlank check"); 2491a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang return true; 2492a49b6846c4f85c1fecc80d176ff88336e596e5fcAlice Yang } 249382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 2494bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 2495bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 2496bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 2497bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 2498bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 2499bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2500bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2501bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 2502bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 2503bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 2504bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2505bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 2506bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 2507bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2508bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2509bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 2510bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 2511bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 2512bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 2513bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2514bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 2515bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 2516bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 2517bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 2518bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 2519bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 2520bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 2521bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 2522bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2523bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 252482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 252582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 252682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 252782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 252882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 252982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 253082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 253182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 2532eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 253382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 253433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 253533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 253682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 2537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 2538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 2539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 2540181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2541181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 2542dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei final boolean orientationChanged, final boolean autoSend) { 2543009b3712ff1657fa839049826451321fdd938d32Mark Wei if (mAccounts == null || mAccount == null) { 2544009b3712ff1657fa839049826451321fdd938d32Mark Wei Toast.makeText(this, R.string.send_failed, Toast.LENGTH_SHORT).show(); 2545dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei if (autoSend) { 2546dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei finish(); 2547dd19b63d3f560aba8962435ed5a2e1f5ae794351Mark Wei } 2548009b3712ff1657fa839049826451321fdd938d32Mark Wei return false; 2549009b3712ff1657fa839049826451321fdd938d32Mark Wei } 2550009b3712ff1657fa839049826451321fdd938d32Mark Wei 2551ff8553f20964f4c31b0c503a9e1daff6ae08a9c7Scott Kennedy final String[] to, cc, bcc; 2552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 2553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 2554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 2555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 2556181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 2557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 2558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2559181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 2561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 2562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 2563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 2564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 2565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2567181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 2568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 2570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 2571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 2572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 2575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 2576181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 2577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 2578181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 2579181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 2580181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 2583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 2585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 25862558b509117872e539a6eaeb72aa63425529d50bTony Mantler boolean emptyBody = TextUtils.getTrimmedLength(mBodyView.getEditableText()) == 0; 2587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 2589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 2590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 2591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 2592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 2594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 2595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 2596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 25972558b509117872e539a6eaeb72aa63425529d50bTony Mantler showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, save, 25982558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 2599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2601181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 26032558b509117872e539a6eaeb72aa63425529d50bTony Mantler showSendConfirmDialog(R.string.confirm_send_message_with_no_body, save, 26042558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 2605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2608181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 2609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 26102558b509117872e539a6eaeb72aa63425529d50bTony Mantler showSendConfirmDialog(R.string.confirm_send_message, save, showToast); 2611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2612181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 26152558b509117872e539a6eaeb72aa63425529d50bTony Mantler sendOrSave(save, showToast); 2616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 2617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2618181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2619181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2620181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 2621181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 26225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang * 2623181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 2624181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2625181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 2626181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 2627181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2628181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2629181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2630181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 2631181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 2632181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 2633181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2634181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 2635181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 2636181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2637181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 26382558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static class SendConfirmDialogFragment extends DialogFragment { 2639f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook // Public no-args constructor needed for fragment re-instantiation 2640f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook public SendConfirmDialogFragment() {} 2641f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook 26422558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static SendConfirmDialogFragment newInstance(final int messageId, 26432558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean save, final boolean showToast) { 26442558b509117872e539a6eaeb72aa63425529d50bTony Mantler final SendConfirmDialogFragment frag = new SendConfirmDialogFragment(); 26452558b509117872e539a6eaeb72aa63425529d50bTony Mantler final Bundle args = new Bundle(3); 26462558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putInt("messageId", messageId); 26472558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putBoolean("save", save); 26482558b509117872e539a6eaeb72aa63425529d50bTony Mantler args.putBoolean("showToast", showToast); 26492558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.setArguments(args); 26502558b509117872e539a6eaeb72aa63425529d50bTony Mantler return frag; 2651181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 26522558b509117872e539a6eaeb72aa63425529d50bTony Mantler 26532558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 26542558b509117872e539a6eaeb72aa63425529d50bTony Mantler public Dialog onCreateDialog(Bundle savedInstanceState) { 26552558b509117872e539a6eaeb72aa63425529d50bTony Mantler final int messageId = getArguments().getInt("messageId"); 26562558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean save = getArguments().getBoolean("save"); 26572558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean showToast = getArguments().getBoolean("showToast"); 26582558b509117872e539a6eaeb72aa63425529d50bTony Mantler 26592558b509117872e539a6eaeb72aa63425529d50bTony Mantler return new AlertDialog.Builder(getActivity()) 26602558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setMessage(messageId) 26612558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setTitle(R.string.confirm_send_title) 26622558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setIconAttribute(android.R.attr.alertDialogIcon) 26632558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setPositiveButton(R.string.send, 26642558b509117872e539a6eaeb72aa63425529d50bTony Mantler new DialogInterface.OnClickListener() { 2665aa27bc0e1c3bb6be4609b00007637a9d3e960f5eScott Kennedy @Override 26662558b509117872e539a6eaeb72aa63425529d50bTony Mantler public void onClick(DialogInterface dialog, int whichButton) { 26672558b509117872e539a6eaeb72aa63425529d50bTony Mantler ((ComposeActivity)getActivity()).finishSendConfirmDialog(save, 26682558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 26692558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 26702558b509117872e539a6eaeb72aa63425529d50bTony Mantler }) 26712558b509117872e539a6eaeb72aa63425529d50bTony Mantler .create(); 26722558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 26732558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 26742558b509117872e539a6eaeb72aa63425529d50bTony Mantler 26752558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void finishSendConfirmDialog(final boolean save, final boolean showToast) { 26762558b509117872e539a6eaeb72aa63425529d50bTony Mantler sendOrSave(save, showToast); 26772558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 26782558b509117872e539a6eaeb72aa63425529d50bTony Mantler 26792558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void showSendConfirmDialog(final int messageId, final boolean save, 26802558b509117872e539a6eaeb72aa63425529d50bTony Mantler final boolean showToast) { 26812558b509117872e539a6eaeb72aa63425529d50bTony Mantler final DialogFragment frag = SendConfirmDialogFragment.newInstance(messageId, save, 26822558b509117872e539a6eaeb72aa63425529d50bTony Mantler showToast); 26832558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.show(getFragmentManager(), "send confirm"); 2684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 2688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 2689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 2690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 2692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 2693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 2697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 2698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 2699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 2701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 2702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 2703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 2704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 2707e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount, 270805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook Message message, final Message refMessage, Spanned body, final CharSequence quotedText, 270944a6339dd80f4b5b9e5d54567021698d92467c5emindyp SendOrSaveCallback callback, Handler handler, boolean save, int composeMode, 271060847256c691b2677772a46919038f9c600fecf7Scott Kennedy ReplyFromAccount draftAccount, final ContentValues extraValues) { 2711b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final ContentValues values = new ContentValues(); 271229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 2713b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final String refMessageId = refMessage != null ? refMessage.uri.toString() : ""; 2714c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira 2715e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putToAddresses(values, message.getToAddresses()); 2716e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCcAddresses(values, message.getCcAddresses()); 2717e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putBccAddresses(values, message.getBccAddresses()); 271829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 27198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy MessageModification.putCustomFromAddress(values, message.getFrom()); 272092551d057965689f1952faeb06763f0762bc717fMindy Pereira 2721e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putSubject(values, message.subject); 2722b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook // Make sure to remove only the composing spans from the Spannable before saving. 2723b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final String htmlBody = Html.toHtml(removeComposingSpans(body)); 272405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook 272529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 272629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 272729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 2728e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 2729e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 2730e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 2731e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 273255271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook final int quoteStartPos = fullBody.length() + pos; 273355271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook fullBody.append(text); 273455271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook MessageModification.putQuoteStartPos(values, quoteStartPos); 273512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 2736e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 273729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 2738e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 2739e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 2740e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 2741e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 274229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 274329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 2744002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = getDraftType(composeMode); 274512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 2746c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (refMessage != null) { 2747c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyHtml)) { 2748c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 2749c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 2750c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyText)) { 2751c59dd8270215f97d39697dae9e69976bcfe3642bmindyp MessageModification.putBody(values, 2752c59dd8270215f97d39697dae9e69976bcfe3642bmindyp Utils.convertHtmlToPlainText(fullBody.toString()).toString()); 2753c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 2754c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } else { 2755c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 2756c59dd8270215f97d39697dae9e69976bcfe3642bmindyp MessageModification.putBody(values, Utils.convertHtmlToPlainText(fullBody.toString()) 2757c59dd8270215f97d39697dae9e69976bcfe3642bmindyp .toString()); 2758c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira } 2759e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putAttachments(values, message.getAttachments()); 276012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 276112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 276212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 276360847256c691b2677772a46919038f9c600fecf7Scott Kennedy if (extraValues != null) { 276460847256c691b2677772a46919038f9c600fecf7Scott Kennedy values.putAll(extraValues); 276560847256c691b2677772a46919038f9c600fecf7Scott Kennedy } 27663c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(context, replyFromAccount, 27673c7f94d02ff557c955c5d191cef45361a10be5c9Paul Westbrook values, refMessageId, message.getAttachments(), save); 276844a6339dd80f4b5b9e5d54567021698d92467c5emindyp SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback, 276944a6339dd80f4b5b9e5d54567021698d92467c5emindyp draftAccount); 277082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2771181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 2772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 2773181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 2774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 277582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2776181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 2777181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 277882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2779b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook /** 2780b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook * Removes any composing spans from the specified string. This will create a new 2781b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook * SpannableString instance, as to not modify the behavior of the EditText view. 2782b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook */ 2783b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook private static SpannableString removeComposingSpans(Spanned body) { 2784b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook final SpannableString messageBody = new SpannableString(body); 2785b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook BaseInputConnection.removeComposingSpans(messageBody); 2786b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook return messageBody; 2787b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook } 2788b4931c62bffec463df9c3871d83a35bbeb9d5920Paul Westbrook 2789002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira private static int getDraftType(int mode) { 2790002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = -1; 2791002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira switch (mode) { 2792002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.COMPOSE: 2793002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.COMPOSE; 2794002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2795002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY: 2796002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY; 2797002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2798002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY_ALL: 2799002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY_ALL; 2800002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2801002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.FORWARD: 2802002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.FORWARD; 2803002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2804002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2805002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira return draftType; 2806002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2807002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira 28082558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void sendOrSave(final boolean save, final boolean showToast) { 2809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 2810181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 28113ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook if (ActivityManager.isUserAMonkey()) { 2812181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 2813181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 281482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28152558b509117872e539a6eaeb72aa63425529d50bTony Mantler final Spanned body = mBodyView.getEditableText(); 28162558b509117872e539a6eaeb72aa63425529d50bTony Mantler 2817181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 28181f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang // FIXME: unused 281982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 282082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28210bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 282282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 2823181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 2824181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 2825181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 2826181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 2827181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 2828181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 2829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 2832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 2834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 2835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2836181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 283782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28380bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 28397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 28407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 2841181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 284244a6339dd80f4b5b9e5d54567021698d92467c5emindyp mDraftAccount = sendOrSaveMessage.mAccount; 2843181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 2844181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 28457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 28467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 28477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2848181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 2849181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 2850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 28527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 2853181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2854181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 285582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28560bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 28577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 28587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 28597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 28607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 28617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 286282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28630bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 28647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 286547d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira // Update the last sent from account. 286647d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira if (mAccount != null) { 286747d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira MailAppProvider.getInstance().setLastSentFromAccount(mAccount.uri.toString()); 286847d0e65536c55d7aad8c902aef31efb41fd05cf2Mindy Pereira } 28697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 28707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 28717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 28727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 28737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 28747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 28757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 28767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 28777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 28787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 287982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 28817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 28827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 28837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 28847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 28857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 288682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 28877ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 28887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 28897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 28907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 28917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 28927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 28937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 28947ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2895181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 2896181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 28971e05a1eedd720aac611c6402c3655ec92c23a43bTony Mantler setAccount(mReplyFromAccount.account); 2898181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2899181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 2900181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 2901181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 2902181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2903181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 2904181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2905181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2906e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message msg = createMessage(mReplyFromAccount, getMode()); 290705b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body, 290805b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mQuotedTextView.getQuotedTextIfIncluded(), callback, 290960847256c691b2677772a46919038f9c600fecf7Scott Kennedy mSendSaveTaskHandler, save, mComposeMode, mDraftAccount, mExtraValues); 2910181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2911181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 2912181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 2913181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 2914181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 2915181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 2916181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 2917181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2918181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2919181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 2920181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 2921181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 2922181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 2923181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2924181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 2925181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2926181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 2927181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2928181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2929181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2930181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2931181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 2932181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 2933181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 2934181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2935181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 2936181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 2937181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 293882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 29392db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira private void doAttach(String type) { 2940013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 2941013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 2942d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 29432db7d4a37b794e1721a5b9416068702aa799c5f8Mindy Pereira i.setType(type); 2944013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 2945181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 2946181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 2947013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 2948013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 2949ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 2950a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 2951ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 2952cd0b0b950efebfc3964334067747b97e61c4f027mindyp mCcBccButton.setVisibility(View.INVISIBLE); 2953ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2954ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2955ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 29564fe0af81874976a1995191321e35c844b2229811Andy Huang private static String getActionString(int action) { 2957dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang final String msgType; 29584fe0af81874976a1995191321e35c844b2229811Andy Huang switch (action) { 2959dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang case COMPOSE: 2960dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang msgType = "new_message"; 2961dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang break; 2962dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang case REPLY: 2963dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang msgType = "reply"; 2964dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang break; 2965dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang case REPLY_ALL: 2966dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang msgType = "reply_all"; 2967dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang break; 2968dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang case FORWARD: 2969dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang msgType = "forward"; 2970dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang break; 2971dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang default: 2972dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang msgType = "unknown"; 2973dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang break; 2974dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang } 29754fe0af81874976a1995191321e35c844b2229811Andy Huang return msgType; 29764fe0af81874976a1995191321e35c844b2229811Andy Huang } 29774fe0af81874976a1995191321e35c844b2229811Andy Huang 29784fe0af81874976a1995191321e35c844b2229811Andy Huang private void logSendOrSave(boolean save) { 29794fe0af81874976a1995191321e35c844b2229811Andy Huang if (!Analytics.isLoggable() || mAttachmentsView == null) { 29804fe0af81874976a1995191321e35c844b2229811Andy Huang return; 29814fe0af81874976a1995191321e35c844b2229811Andy Huang } 29824fe0af81874976a1995191321e35c844b2229811Andy Huang 29834fe0af81874976a1995191321e35c844b2229811Andy Huang final String category = (save) ? "message_save" : "message_send"; 29844fe0af81874976a1995191321e35c844b2229811Andy Huang final int attachmentCount = getAttachments().size(); 29854fe0af81874976a1995191321e35c844b2229811Andy Huang final String msgType = getActionString(mComposeMode); 2986dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang final String label; 2987dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang final long value; 2988dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang if (mComposeMode == COMPOSE) { 2989dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang label = Integer.toString(attachmentCount); 2990dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang value = attachmentCount; 2991dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang } else { 2992dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang label = null; 2993dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang value = 0; 2994dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang } 2995dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang Analytics.getInstance().sendEvent(category, msgType, label, value); 2996dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang } 2997dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang 2998326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2999326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 3000a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 3001326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 3002326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 3003326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 3004326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 3005326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 3006326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 3007326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3008cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira clearChangeListeners(); 3009a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 3010154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 301168c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp if (mRefMessage != null) { 30120aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy setFieldsFromRefMessage(mComposeMode); 30138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 3014ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showCc = false; 3015ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showBcc = false; 3016ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mDraft != null) { 3017ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Following desktop behavior, if the user has added a BCC 3018ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // field to a draft, we show it regardless of compose mode. 30198960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy showBcc = !TextUtils.isEmpty(mDraft.getBcc()); 3020ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Use the draft to determine what to populate. 3021ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // If the Bcc field is showing, show the Cc field whether it is populated or not. 30228960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy showCc = showBcc 30238960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy || (!TextUtils.isEmpty(mDraft.getCc()) && mComposeMode == REPLY_ALL); 302468c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp } 302568c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp if (mRefMessage != null) { 30269b1ac57b10316cc1416c46f04811c54830e01529mindyp showCc = !TextUtils.isEmpty(mCc.getText()); 302768c0bfcc4c5ee390305b6f677dc43ad0036371d8mindyp showBcc = !TextUtils.isEmpty(mBcc.getText()); 3028ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } 3029ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 3030a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 3031ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira updateHideOrShowCcBcc(); 3032cbfb75a0f92a3ef5cf10ab94b451e4898cc78bfcMindy Pereira initChangeListeners(); 3033326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 3034326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3035326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 3036b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira @VisibleForTesting 3037b3112a2bf7b805695259e412b0e2bc0e0e73e9d6Mindy Pereira protected void resetMessageForModeChange() { 3038154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 3039154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 3040154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 3041154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 3042154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 3043154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 3044154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 3045154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 3046154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 3047154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 3048154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 3049154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 3050154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 3051154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 3052154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 3053154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 3054154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 3055154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 3056154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 3057154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 3058154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 3059154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 3060326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 3061326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 3062326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 3063326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 3064326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 3065326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 3066326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 3067326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3068326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 3069326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 3070326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 3071326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 3072326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3073326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 3074326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3075326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 3076326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 3077326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 3078326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 3079326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 3080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3081326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 3082326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 3083326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 3084326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 308546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 308646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 308746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 308846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 308940882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(false); 30901623f9bfde8ced840a52820da28a0939bcaa32f9mindyp mRespondedInline = true; 309109dd373fae26156a847bb99d88474a7538b9e7c1mindyp if (!mBodyView.hasFocus()) { 30928654d4fcc09ba68872e677b2a57877a46d27fdb5mindyp mBodyView.requestFocus(); 309309dd373fae26156a847bb99d88474a7538b9e7c1mindyp } 309446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 309546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 309646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 309746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 309846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 309946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 310046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 310146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 310246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 310346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 3104eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 310546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 310646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 310746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 310846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 310946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 311046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 311146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 311246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 311346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 3114bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 311546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 311646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 311746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 311846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 3119eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 3120bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 3121bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 3122bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 3123bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 3124bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 3125bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 3126b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira String newSignature = mCachedSettings != null ? mCachedSettings.signature : null; 3127433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira boolean hasFocus = mBodyView.hasFocus(); 31282708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp int signaturePos = getSignatureStartPosition(mSignature, mBodyView.getText().toString()); 31292708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp if (!TextUtils.equals(newSignature, mSignature) || signaturePos < 0) { 3130b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mSignature = newSignature; 31312708306e0b6f8dde22b2571d0dbcc28a53c9f29bmindyp if (!TextUtils.isEmpty(mSignature)) { 3132b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira // Appending a signature does not count as changing text. 3133b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.removeTextChangedListener(this); 3134b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 3135b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.addTextChangedListener(this); 3136b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira } 3137433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (hasFocus) { 3138433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 3139433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 3140bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 3141bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 3142bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 3143bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 3144bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 3145bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 3146bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 3147bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 3148bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 314946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 31501a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 31515a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 31525a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 315392551d057965689f1952faeb06763f0762bc717fMindy Pereira mReplyFromAccount = mFromSpinner.getCurrentAccount(); 315492551d057965689f1952faeb06763f0762bc717fMindy Pereira if (!mAccount.equals(mReplyFromAccount.account)) { 3155f432dbce53a73eabed150b35033f2ec1a70c9725mindyp // Clear a signature, if there was one. 3156f432dbce53a73eabed150b35033f2ec1a70c9725mindyp mBodyView.removeTextChangedListener(this); 3157f432dbce53a73eabed150b35033f2ec1a70c9725mindyp String oldSignature = mSignature; 3158f432dbce53a73eabed150b35033f2ec1a70c9725mindyp String bodyText = getBody().getText().toString(); 3159f432dbce53a73eabed150b35033f2ec1a70c9725mindyp if (!TextUtils.isEmpty(oldSignature)) { 3160f432dbce53a73eabed150b35033f2ec1a70c9725mindyp int pos = getSignatureStartPosition(oldSignature, bodyText); 3161f432dbce53a73eabed150b35033f2ec1a70c9725mindyp if (pos > -1) { 3162f432dbce53a73eabed150b35033f2ec1a70c9725mindyp mBodyView.setText(bodyText.substring(0, pos)); 3163f432dbce53a73eabed150b35033f2ec1a70c9725mindyp } 3164f432dbce53a73eabed150b35033f2ec1a70c9725mindyp } 3165b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(mReplyFromAccount.account); 3166f432dbce53a73eabed150b35033f2ec1a70c9725mindyp mBodyView.addTextChangedListener(this); 3167181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 3168181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 3169181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 3170181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 3171181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 3172181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 3173181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 3174181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 317582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 31761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 317782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 317882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 317982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 318082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 318182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 318282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 318382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 31842558b509117872e539a6eaeb72aa63425529d50bTony Mantler public static class DiscardConfirmDialogFragment extends DialogFragment { 3185f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook // Public no-args constructor needed for fragment re-instantiation 3186f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook public DiscardConfirmDialogFragment() {} 3187f0ea4849bf7a2c11f99ca0b42307ae8ba665b1dcPaul Westbrook 31882558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 31892558b509117872e539a6eaeb72aa63425529d50bTony Mantler public Dialog onCreateDialog(Bundle savedInstanceState) { 31902558b509117872e539a6eaeb72aa63425529d50bTony Mantler return new AlertDialog.Builder(getActivity()) 31912558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setMessage(R.string.confirm_discard_text) 31922558b509117872e539a6eaeb72aa63425529d50bTony Mantler .setPositiveButton(R.string.discard, 31932558b509117872e539a6eaeb72aa63425529d50bTony Mantler new DialogInterface.OnClickListener() { 31942558b509117872e539a6eaeb72aa63425529d50bTony Mantler @Override 31952558b509117872e539a6eaeb72aa63425529d50bTony Mantler public void onClick(DialogInterface dialog, int which) { 31962558b509117872e539a6eaeb72aa63425529d50bTony Mantler ((ComposeActivity)getActivity()).doDiscardWithoutConfirmation(); 31972558b509117872e539a6eaeb72aa63425529d50bTony Mantler } 31982558b509117872e539a6eaeb72aa63425529d50bTony Mantler }) 31992b215b7e4aa5901322dd6ef2e4e8616a4552e9b3Tony Mantler .setNegativeButton(R.string.cancel, null) 32002558b509117872e539a6eaeb72aa63425529d50bTony Mantler .create(); 320182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 320282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 320382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 3204efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 32052558b509117872e539a6eaeb72aa63425529d50bTony Mantler final DialogFragment frag = new DiscardConfirmDialogFragment(); 32062558b509117872e539a6eaeb72aa63425529d50bTony Mantler frag.show(getFragmentManager(), "discard confirm"); 3207efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 320882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 320982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 321082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 321182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 321282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 321382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 32142558b509117872e539a6eaeb72aa63425529d50bTony Mantler private void doDiscardWithoutConfirmation() { 32157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 321682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 321782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 3218b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 321978ea8e20c7d678c79153a1f814d0740f2bf3e462Marc Blank if (!mAccount.expungeMessageUri.equals(Uri.EMPTY)) { 3220cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 3221cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 32220bbc858506c95005f2840fa5dff495a9216d2665Marc Blank getContentResolver().delete(mDraft.uri, null, null); 3223cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 322482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 322582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 322682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 322782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 322882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 322982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 323082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 323182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 32322558b509117872e539a6eaeb72aa63425529d50bTony Mantler // Display a toast to let the user know 32332558b509117872e539a6eaeb72aa63425529d50bTony Mantler Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 323482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 323582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 323682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 3237dc97bf4509c450c9121b79ec4668e0f9b34f0690Andy Huang mPerformedSendOrDiscard = true; 323882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 323982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 324082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 3241eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 3242eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 3243eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 3244eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 3245eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 3246eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 3247eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 3248eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 3249eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 325048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira doSave(!mAddingAttachment /* show toast */); 3251eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 3252eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 3253eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 3254eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 3255eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 3256eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 325740882430c874ff29890ec6fa31f7649788cbc470mindyp // If we are showing any attachments, make sure we have an upper 325840882430c874ff29890ec6fa31f7649788cbc470mindyp // divider. 325940882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 3260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 3261eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 326275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 326340882430c874ff29890ec6fa31f7649788cbc470mindyp @Override 326440882430c874ff29890ec6fa31f7649788cbc470mindyp public void onAttachmentAdded() { 326540882430c874ff29890ec6fa31f7649788cbc470mindyp mQuotedTextView.setUpperDividerVisible(mAttachmentsView.getAttachments().size() > 0); 326640882430c874ff29890ec6fa31f7649788cbc470mindyp mAttachmentsView.focusLastAttachment(); 326740882430c874ff29890ec6fa31f7649788cbc470mindyp } 326875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 326975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 327075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 327175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 32720bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 327375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 327475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 327575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 327675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 327775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 327875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 327975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 328075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 328175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 328275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 32830bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 328475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 328575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 328675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 328775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 328875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 328975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 329075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 329175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 329275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 329375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 329475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 329575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 329675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 329775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 329875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 329975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 330075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 330175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 330275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 330375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 330475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 330575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 330675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 330775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 330875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 330975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 331075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 331175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 331275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 331375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 331475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 331575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 331675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 331775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 331875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 331975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 332075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 332175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 332275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 332375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 332475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 332575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 332675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 332775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 332875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 332975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 333075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 333175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 333275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 333375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 333475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 333575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 333675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 333775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 333875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 333975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 334075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 334175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 334275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 334375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 334475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 334575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 334675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 334775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 334875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 334975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 335075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 335175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 335275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 335375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 335475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 335575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 335675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 335775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 335875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 335975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 336075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 336175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 336275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 3363e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 3364e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) { 3365e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (sTestSendOrSaveCallback != null && testCallback != null) { 3366e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira throw new IllegalStateException("Attempting to register more than one test callback"); 3367e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 3368e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira sTestSendOrSaveCallback = testCallback; 3369e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 3370bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira 3371bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira @VisibleForTesting 3372bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira protected ArrayList<Attachment> getAttachments() { 3373bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira return mAttachmentsView.getAttachments(); 3374bddd6f39f34aa15fed2e757f7d3e4163272ca02cMindy Pereira } 337596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 337696a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 337796a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public Loader<Cursor> onCreateLoader(int id, Bundle args) { 337896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira switch (id) { 3379a990a715012379451344246c5156d29938f12886Alice Yang case INIT_DRAFT_USING_REFERENCE_MESSAGE: 3380a990a715012379451344246c5156d29938f12886Alice Yang return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null, 3381a990a715012379451344246c5156d29938f12886Alice Yang null, null); 338296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira case REFERENCE_MESSAGE_LOADER: 338396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return new CursorLoader(this, mRefMessageUri, UIProvider.MESSAGE_PROJECTION, null, 338496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira null, null); 3385b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case LOADER_ACCOUNT_CURSOR: 3386b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return new CursorLoader(this, MailAppProvider.getAccountsUri(), 3387b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira UIProvider.ACCOUNTS_PROJECTION, null, null, null); 338896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 338996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira return null; 339096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 339196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 339296a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 339396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 3394b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira int id = loader.getId(); 3395b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira switch (id) { 3396a990a715012379451344246c5156d29938f12886Alice Yang case INIT_DRAFT_USING_REFERENCE_MESSAGE: 3397b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (data != null && data.moveToFirst()) { 3398b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mRefMessage = new Message(data); 3399b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Intent intent = getIntent(); 3400a990a715012379451344246c5156d29938f12886Alice Yang initFromRefMessage(mComposeMode); 3401a990a715012379451344246c5156d29938f12886Alice Yang finishSetup(mComposeMode, intent, null); 3402a990a715012379451344246c5156d29938f12886Alice Yang if (mComposeMode != FORWARD) { 3403b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira String to = intent.getStringExtra(EXTRA_TO); 3404b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (!TextUtils.isEmpty(to)) { 34050aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy mRefMessage.setTo(null); 34060aeaf7d8c2ee4bc882ca901531f985c61b4cc7c7Scott Kennedy mRefMessage.setFrom(null); 3407b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira clearChangeListeners(); 3408b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira mTo.append(to); 3409b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initChangeListeners(); 3410b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3411b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3412b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 3413b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finish(); 341496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 3415b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 3416a990a715012379451344246c5156d29938f12886Alice Yang case REFERENCE_MESSAGE_LOADER: 3417a990a715012379451344246c5156d29938f12886Alice Yang // Only populate mRefMessage and leave other fields untouched. 3418a990a715012379451344246c5156d29938f12886Alice Yang if (data != null && data.moveToFirst()) { 3419a990a715012379451344246c5156d29938f12886Alice Yang mRefMessage = new Message(data); 3420a990a715012379451344246c5156d29938f12886Alice Yang } 34219f855d667e34fbf0d330845225c26956e540b819Andy Huang finishSetup(mComposeMode, getIntent(), mInnerSavedState); 3422a990a715012379451344246c5156d29938f12886Alice Yang break; 3423b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira case LOADER_ACCOUNT_CURSOR: 3424b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (data != null && data.moveToFirst()) { 3425b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // there are accounts now! 3426b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira Account account; 3427faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook final ArrayList<Account> accounts = new ArrayList<Account>(); 3428faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook final ArrayList<Account> initializedAccounts = new ArrayList<Account>(); 3429b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira do { 3430b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = new Account(data); 3431dfa1dec0cfdc263c51e971dc3c41b90386a24340Paul Westbrook if (account.isAccountReady()) { 3432b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira initializedAccounts.add(account); 3433b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3434b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira accounts.add(account); 3435b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } while (data.moveToNext()); 3436b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (initializedAccounts.size() > 0) { 3437b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.wait).setVisibility(View.GONE); 3438b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira getLoaderManager().destroyLoader(LOADER_ACCOUNT_CURSOR); 3439b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.compose).setVisibility(View.VISIBLE); 3440faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook mAccounts = initializedAccounts.toArray( 3441faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook new Account[initializedAccounts.size()]); 3442faa742fcff868e17fb7e78c4c3f3ffdb01386f57Paul Westbrook 3443b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira finishCreate(); 3444b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira invalidateOptionsMenu(); 3445b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } else { 3446b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira // Show "waiting" 3447b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira account = accounts.size() > 0 ? accounts.get(0) : null; 3448b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira showWaitFragment(account); 3449b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3450b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3451b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira break; 3452b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3453b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3454b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 3455b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private void showWaitFragment(Account account) { 3456b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira WaitFragment fragment = getWaitFragment(); 3457b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira if (fragment != null) { 3458b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragment.updateAccount(account); 345996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } else { 3460b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira findViewById(R.id.wait).setVisibility(View.VISIBLE); 3461b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira replaceFragment(WaitFragment.newInstance(account, true), 3462b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira FragmentTransaction.TRANSIT_FRAGMENT_OPEN, TAG_WAIT); 346396a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 346496a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 346596a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira 3466b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private WaitFragment getWaitFragment() { 3467b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return (WaitFragment) getFragmentManager().findFragmentByTag(TAG_WAIT); 3468b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3469b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 3470b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira private int replaceFragment(Fragment fragment, int transition, String tag) { 3471b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 3472b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.setTransition(transition); 3473b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira fragmentTransaction.replace(R.id.wait, fragment, tag); 3474b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira final int transactionId = fragmentTransaction.commitAllowingStateLoss(); 3475b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira return transactionId; 3476b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira } 3477b199d172dcb568e2c09ea60eeb109922eec2f07eMindy Pereira 347896a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira @Override 347996a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira public void onLoaderReset(Loader<Cursor> arg0) { 348096a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira // Do nothing. 348196a7f7aa2de33b1722009a9ee77d2b7b18a8e3e9Mindy Pereira } 348283e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook 348383e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook @Override 348483e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook public Context getActivityContext() { 348583e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook return this; 348683e6b574cffd06164cad18ee388237a9427ceb3fPaul Westbrook } 34871f8f4dd8c53e6c18ae642235335ce492c9d1e520Andy Huang} 3488