ComposeActivity.java revision 12575866e5526e45eaf773c6c98c93c3a06fe156
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/** 28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc. 38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License. 68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at 78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software 118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and 148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License. 158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */ 168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose; 188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar; 2082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager; 2182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog; 2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog; 23326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar.OnNavigationListener; 248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.app.Activity; 25181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.app.LoaderManager.LoaderCallbacks; 266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver; 2782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues; 286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context; 29181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.CursorLoader; 3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface; 316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent; 32181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.Loader; 3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo; 347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor; 356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri; 368e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle; 3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler; 3882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread; 39f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable; 4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns; 4146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable; 4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html; 4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned; 44c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils; 4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher; 4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token; 47c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport android.view.Gravity; 49326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater; 50b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu; 51b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater; 52b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem; 538e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View; 54326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.ViewGroup; 558e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener; 56eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection; 57326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 591f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView; 606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 61013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 627b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 63c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 64eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener; 659932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 665a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 6730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 6833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 7030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 713ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 7282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 73181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 7430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 7512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 7630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R; 7792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 80c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.ex.chips.RecipientEditTextView; 8146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 8282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 8746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 88bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 8946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 9075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 9146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 9246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 931c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 94bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 9582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 9646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 9746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 985a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira RespondInlineListener, DialogInterface.OnClickListener, TextWatcher, 99181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira AttachmentDeletedListener, OnAccountChangedListener, LoaderCallbacks<Cursor> { 1006349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 101bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook static final int COMPOSE = -1; 1026349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira static final int REPLY = 0; 1036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira static final int REPLY_ALL = 1; 1046349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira static final int FORWARD = 2; 105bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook static final int EDIT_DRAFT = 3; 1066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 1086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private static final String EXTRA_ACTION = "action"; 1096349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String GMAIL_FROM = "gmailfrom"; 1158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 1218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_TO = "to"; 1228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC }; 1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 12982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 13082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 13182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 13282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Key used to store the above map 14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids"; 1436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 151f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook static final String EXTRA_ATTACHMENTS = "attachments"; 152f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 1543ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 155bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // If this is an action to edit an existing draft messagge, this extra will hold the 156bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 157bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 1584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 159013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final String LOG_TAG = new LogUtils().getLogTag(); 160013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 161013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 162013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 163181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private static final int ACCOUNT_SETTINGS_LOADER = 0; 1648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 1658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 1668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Max size for attachments (5 megs). Will be overridden by account settings if found. 1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp): read this from account settings? 1698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024; 1708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 17382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 17482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 175c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 176c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 177c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 1788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 1798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 1807b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 18133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private Account mAccount; 182181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 18382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 1846349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 1856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 186326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 187326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private int mComposeMode = -1; 18846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 18946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private String mRecipient; 19046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 191eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private TextView mBodyView; 1921a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 1932eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 194eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 1955a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira private FromAddressSpinner mFromSpinner; 196013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 197eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 19882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 19982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 20082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 20182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 20282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private AlertDialog mRecipientErrorDialog; 203eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private AlertDialog mSendConfirmDialog; 2043ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private Message mRefMessage; 2057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 2077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 2081f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira private ImageView mAttachmentsButton; 2093ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 210326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 211326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 212326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 2133ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 214bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook launch(launcher, account, message, EDIT_DRAFT); 215326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 216326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2176349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 22033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 2216349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launch(launcher, account, null, COMPOSE); 2226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2273ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 2283ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY); 2296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2343ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 2353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY_ALL); 2366349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 2423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, FORWARD); 2436349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2453ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static void launch(Context launcher, Account account, Message message, int action) { 2466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 250bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 251bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 252bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 253bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 254bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 2556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 2588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 2598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onCreate(Bundle savedInstanceState) { 2608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 2618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 26246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 263818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 26492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 26592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook Account account = (Account)intent.getParcelableExtra(Utils.EXTRA_ACCOUNT); 26692227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (account == null) { 26792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this); 26892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (syncingAccounts.length > 0) { 26992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook account = syncingAccounts[0]; 27092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 27192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 27292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 27392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 274818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 275818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 276818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 27746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 2783ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 27929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 2808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (mRefMessage != null) { 2818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromRefMessage(action, mAccount.name); 2828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 283bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else if (action == EDIT_DRAFT) { 284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Initialize the message from the message in the intent 285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final Message message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 287bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook initFromMessage(message); 288bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 289bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 290bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 291bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 292bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 293bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 294bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 295bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 296bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 297bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 299bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 300bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 302bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 303bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 304bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 3058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 3068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromExtras(intent); 307bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 308bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 309bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == COMPOSE) { 310eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mQuotedTextView.setVisibility(View.GONE); 31146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 312818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira initRecipients(); 313f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook initAttachmentsFromIntent(intent); 3141a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira initActionBar(action); 3155a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira initFromSpinner(); 31675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 3171a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 3181a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 3191a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 3201a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 3211a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 3221a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 3231a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 324818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 325818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mFromSpinner.asyncInitFromSpinner(); 326818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 3271a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 3281a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 329eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 330eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 331eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 332eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 333eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mSendConfirmDialog != null) { 334eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mSendConfirmDialog.dismiss(); 335eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 336eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mRecipientErrorDialog != null) { 337eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mRecipientErrorDialog.dismiss(); 338eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 339eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 340eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveIfNeeded(); 341eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 342eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 343eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 344eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 345eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAddingAttachment = false; 346eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 347eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) { 348eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 349eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 350eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 351eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 352eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 353eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public final void onSaveInstanceState(Bundle state) { 354eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 355eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 356eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // onSaveInstanceState is only called if the user might come back to this activity so it is 357eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // not an ideal location to save the draft. However, if we have never saved the draft before 358eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // we have to save it here in order to have an id to save in the bundle. 359eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveIfNeededOnOrientationChanged(); 360eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 361eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 362818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 363818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 36423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira assert(account != null); 36523e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 36623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 36723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this); 369818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 370818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 3711a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private void initFromSpinner() { 3725a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner.setCurrentAccount(mAccount); 3735a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner.asyncInitFromSpinner(); 374eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira boolean showSpinner = mFromSpinner.getCount() > 1; 375eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // If there is only 1 account, just show that account. 376eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // Otherwise, give the user the ability to choose which account to send 377eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // mail from / save drafts to. 378eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromStatic.setVisibility( 379eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira showSpinner ? View.GONE : View.VISIBLE); 3802eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText.setText(mAccount.name); 381eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper.setVisibility( 382eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira showSpinner ? View.VISIBLE : View.GONE); 38346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 38446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 38546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 386a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 3878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 3888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 3898e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 3908e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 3917b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 3921f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment); 3931f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira if (mAttachmentsButton != null) { 3941f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton.setOnClickListener(this); 3951f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira } 396818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 397818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 398818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 39982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 40082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 4016349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 40246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 40346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 404eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView = (TextView) findViewById(R.id.body); 4051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 4062eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 407eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 4085a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 409326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 410326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 41175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 41275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 41375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 41475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 41575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 41675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 41775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this)); 41875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this)); 41975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this)); 42075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 421818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 42275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 42375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 424326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private void initActionBar(int action) { 425326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = action; 426eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 427326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (action == ComposeActivity.COMPOSE) { 428eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 429eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 430326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 431eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 432326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 433326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 434326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 435eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 436eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 437326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira switch (action) { 438326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 439eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 440326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 441326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 442eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 443326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 444326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 445eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 446326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 447326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 4486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 449fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 450fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 451fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 4526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 4536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 45446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void initFromRefMessage(int action, String recipientAddress) { 4558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 4568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 4578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 4588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 4598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 4608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initRecipientsFromRefMessage(recipientAddress, mRefMessage, action); 4618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initBodyFromRefMessage(mRefMessage, action); 4628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 4638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 4646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 4658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira updateHideOrShowCcBcc(); 466c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 467c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 468bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void initFromMessage(Message message) { 469bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook LogUtils.d(LOG_TAG, "Intializing draft from previous draft message"); 470bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 471bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 472bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 473bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 474bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 475bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final List<String> toAddresses = Arrays.asList(message.getToAddresses()); 476bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 477bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses); 478bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addBccAddresses(Arrays.asList(message.getBccAddresses())); 479bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 480bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 481bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 482bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mBodyView.setText(Html.fromHtml(message.bodyHtml)); 483bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 484bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mBodyView.setText(message.bodyText); 485bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 486bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 487bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // TODO: load attachments from the previous message 488bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // TODO: set the from address spinner to the right from account 489bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // TODO: initialize quoted text value 490bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 491bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 4928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 4938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 4948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 4958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 4968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 4978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 4988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 4998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 5008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 5018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 5028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromExtras(Intent intent) { 5038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 5058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 5068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 5078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 5088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 5098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 5108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 5118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!GMAIL_FROM.equals(dataUri.getScheme())) { 5128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 5138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 5148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 5158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(toText.split(","))); 5168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 5228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 5238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 5248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 5268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 5278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 5288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 5308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 5318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 5328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 5358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 5368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 5378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 5408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 5418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 5428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 5438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(value.split(","))); 5448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 5458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(value.split(",")), null); 5468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 5478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(value.split(","))); 5488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 5498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 5508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 5518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 5528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 5578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 5588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final String action = intent.getAction(); 5598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 5608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 5618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 5628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp): read this from account settings. 5658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int maxSize = DEFAULT_MAX_ATTACHMENT_SIZE; 5668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int totalSize = 0; 5678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 5688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Take care of attachments passed in by the extras. 5698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!mAttachmentsChanged) { 5708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras.containsKey(EXTRA_ATTACHMENTS)) { 5718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 5728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String uriString : uris) { 5738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri uri = Uri.parse(uriString); 5748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira long size; 5758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 5768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira size = mAttachmentsView.addAttachment(mAccount, uri, 5778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira false /* doSave */, true /* local file */); 5788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (AttachmentFailureException e) { 5798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // A toast has already been shown to the user, 5808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // just break out of the loop. 5818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 5828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira finish(); 5838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira return; 5848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mAttachmentsChanged = true; 5878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 5888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if ((Intent.ACTION_SEND.equals(action) 5898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira || AUTO_SEND_ACTION.equals(action)) 5908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira && extras.containsKey(Intent.EXTRA_STREAM)) { 5918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 5928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 5938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mAttachmentsView.addAttachment(mAccount, uri, true /* doSave */, 5948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* local file */); 5958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (AttachmentFailureException e) { 5968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // A toast has already been shown to the user, so just 5978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // exit. 5988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 5998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira finish(); 6008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira return; 6018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (Intent.ACTION_SEND_MULTIPLE.equals(action) 6058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira && extras.containsKey(Intent.EXTRA_STREAM)) { 6068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); 6078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Parcelable uri : uris) { 6088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 6098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mAttachmentsView.addAttachment(mAccount, 6108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira (Uri) uri, false /* doSave */, true /* local file */); 6118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (AttachmentFailureException e) { 6128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // A toast has already been shown to the user, 6138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // just break out of the loop. 6148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 6158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira finish(); 6168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira return; 6178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mAttachmentsChanged = true; 6208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira updateHideOrShowCcBcc(); 6258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 6288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 6298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: handle the case where there are spaces in the display name as well as the email 6308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // such as "Guy with spaces <guy+with+spaces@gmail.com>" as they it could be encoded 6318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // ambiguously. 6328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 6348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 6358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 6368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String replacePlus = s.replace("+", "%2B"); 6378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME); 6388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 6418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 6428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 6438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 6448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 6458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 6468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 6478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 6488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 6498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 6508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 6518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 6528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 6538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 6548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 6558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 6568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 6578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(to.split(" ,"))); 6598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 6608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 6618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 6628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 6638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 6648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 6688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 6698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 6718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 6728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 6748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 6758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 6778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 6788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 6798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME)); 6808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 6818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 6828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 6838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 6878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 6888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 6898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME), 6908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 6918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 6928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 6938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira updateHideOrShowCcBcc(); 6978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6993ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void initAttachments(Message refMessage) { 7007a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira mAttachmentsView.addAttachments(mAccount, refMessage); 701eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 702eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 703f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 704f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Bundle extras = intent.getExtras(); 705f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 706f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 707f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 708f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 709f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 710f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 711f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 712f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 713f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 714f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook size = mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */, 715f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook true /* local file */); 716f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 717f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 718f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 719f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 720f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 721f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 722f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 723f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 724f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) { 725f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 726f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 727f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 728f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook size = mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */, 729f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook true /* local file */); 730f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 731f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, so just 732f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // exit. 733f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 734f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 735f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 736f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 737f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 738f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND_MULTIPLE.equals(action) 739f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook && extras.containsKey(Intent.EXTRA_STREAM)) { 740f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); 741f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (Parcelable uri : uris) { 742f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 743f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 744bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook size = mAttachmentsView.addAttachment(mAccount, (Uri) uri, 745f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook false /* doSave */, true /* local file */); 746f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 747f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 748f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 749f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 750f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 751f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 752f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 753f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 754f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 755f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 756f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 757f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 758f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 759f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 760f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 761f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 762f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 7633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void initBodyFromRefMessage(Message refMessage, int action) { 7649932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (action == REPLY || action == REPLY_ALL || action == FORWARD) { 7659932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 7669932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 76746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 76846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 76946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 770ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 771a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira boolean ccVisible = !TextUtils.isEmpty(mCc.getText()); 772a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira boolean bccVisible = !TextUtils.isEmpty(mBcc.getText()); 773a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (ccVisible || bccVisible) { 774a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(false, ccVisible, bccVisible); 775a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 776ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 777ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!mCc.isShown() || !mBcc.isShown()) { 778ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 779ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setText(getString(!mCc.isShown() ? R.string.add_cc_label 780ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 781ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 782ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 783ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 784ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 78546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 78646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 787013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 788013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 789013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 790013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 791013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 792013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Uri uri = data != null ? data.getData() : null; 793013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 794f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira long size = mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */, 795f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira true /* local file */); 7969932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 7979932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 7989932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 799013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 8009932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 8019932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // A toast has already been shown to the user, no need to do 8029932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // anything. 8039932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 804013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 805013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 806013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 8073ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initRecipientsFromRefMessage(String recipientAddress, Message refMessage, 80846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action) { 8094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 8104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 8114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 8124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 81333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira initReplyRecipients(mAccount.name, refMessage, action); 8144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 816818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 8173ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initReplyRecipients(String account, Message refMessage, int action) { 8184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // This is the email address of the current user, i.e. the one composing 8194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the reply. 8204a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String accountEmail = Address.getEmailAddress(account).getAddress(); 8213ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String fromAddress = refMessage.from; 8223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to); 8233ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String replytoAddress = refMessage.replyTo; 824a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 8254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 8264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 8274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 8284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 829a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 830a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 8313ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 8323ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 833a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 834a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 8354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 8363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 8373ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 838154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 8394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addRecipients(accountEmail, ccAddresses, sentToAddresses); 8403ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira addRecipients(accountEmail, ccAddresses, 8413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira Utils.splitCommaSeparatedString(refMessage.cc)); 8424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 8434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 8464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 8474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 8484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 8504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 8518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 8528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 8534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 855bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 856bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 857bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 858bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 8594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 8604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 8614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 8624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 8634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 8648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 8658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 8668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 8678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 8684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 8694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 8728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 8738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 8748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 8758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 8768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 8778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 8788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 8798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 8808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 8864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) { 8874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira HashSet<String> hash = new HashSet<String>(); 8884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (Rfc822Token[] tokens : list) { 8894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 8904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 8914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 8944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 8954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 8964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 8974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 8984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 8994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 9014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 9024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 9044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 9074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 9084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 9094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 9104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addAddressToList(String address, RecipientEditTextView list) { 9144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 9154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 9164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 9184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 9204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 9214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 9254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected Collection<String> initToRecipients(String account, String accountEmail, 9263ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String senderAddress, String replyToAddress, String[] inToAddresses) { 9274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 9284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 9294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 9304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 9314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 9324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 9333ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira if (!TextUtils.isEmpty(replyToAddress)) { 9343ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 9354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 9363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(senderAddress); 9374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 9394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static void addRecipients(String account, Set<String> recipients, String[] addresses) { 9424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String email : addresses) { 9434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Do not add this account, or any of the custom froms, to the list 9444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // of recipients. 9454a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 9464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (!account.equalsIgnoreCase(recipientAddress)) { 9474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 9484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 95046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 95146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 9523ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void setSubject(Message refMessage, int action) { 9533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String subject = refMessage.subject; 95446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 95546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 95646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 95746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 95846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 95946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.forward_subject_label); 96046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 96146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.reply_subject_label); 96246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 96346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 96446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 96546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (subject.toLowerCase().startsWith(prefix.toLowerCase())) { 96646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 96746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 96846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = String 96946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira .format(getString(R.string.formatted_subject), prefix, subject); 97046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 97146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mSubject.setText(correctedSubject); 97246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 97346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 974818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 975818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 976818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 977818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 978eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 979eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 980818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 981679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 982c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira view.setTokenizer(new Rfc822Tokenizer()); 98382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 984679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook final String accountName = mAccount.name; 98533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 98633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 987c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira if (offset > -1) { 98833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira account = account.substring(accountName.indexOf("@") + 1); 989c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 99082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 991c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 99282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 9938e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 9948e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 9958e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 9968e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 9978e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira int id = v.getId(); 9988e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira switch (id) { 999a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira case R.id.add_cc_bcc: 10008e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Verify that cc/ bcc aren't showing. 10018e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Animate in cc/bcc. 1002a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira showCcBccViews(); 10038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira break; 10041f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.add_attachment: 10051f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira doAttach(); 10061f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 10078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 10088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1009b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1010b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1011b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 1012b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira super.onCreateOptionsMenu(menu); 1013b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1014b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 101582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 101682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 1017b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1018b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1019b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1020b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1021ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 1022ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 1023818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 1024ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1025ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 1026ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 1027ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 1028ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 1029ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 1030ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1031ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1032ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 1033ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1034ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 103575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (mSave != null) { 103675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSave.setEnabled(shouldSave()); 103775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 1038ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 1039ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1040ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1041ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 1042b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 1043b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira int id = item.getItemId(); 104475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 1045b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira switch (id) { 10467b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira case R.id.add_attachment: 1047013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira doAttach(); 10487b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira break; 1049ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira case R.id.add_cc_bcc: 1050ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira showCcBccViews(); 1051b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira break; 105233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.save: 1053eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSave(true, false); 105433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 105533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.send: 105633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira doSend(); 105775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira break; 1058efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira case R.id.discard: 1059efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira doDiscard(); 1060efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira break; 10611f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.settings: 10621f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira Utils.showSettings(this, mAccount); 10631f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 1064fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case android.R.id.home: 1065fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira finish(); 1066fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1067fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.help_info_menu_item: 1068fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira // TODO: enable context sensitive help 1069fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira Utils.showHelp(this, mAccount.helpIntentUri, null); 1070fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1071fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.feedback_menu_item: 1072fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira Utils.sendFeedback(this, mAccount); 1073fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 107475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira default: 107575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira handled = false; 107633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 1077b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1078b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 1079b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 108133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 108282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira sendOrSaveWithSanityChecks(false, true, false); 108333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 108433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 1085eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void doSave(boolean showToast, boolean resetIME) { 1086eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira sendOrSaveWithSanityChecks(true, showToast, false); 1087eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (resetIME) { 1088eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // Clear the IME composing suggestions from the body. 1089eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira BaseInputConnection.removeComposingSpans(mBodyView.getEditableText()); 1090eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 109182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 109282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 109382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ interface SendOrSaveCallback { 109482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 10957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 10967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 109782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 109882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 109982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 110082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ static class SendOrSaveTask implements Runnable { 110182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 110282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final SendOrSaveCallback mSendOrSaveCallback; 110382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 110482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final SendOrSaveMessage mSendOrSaveMessage; 110582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 110682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 110782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira SendOrSaveCallback callback) { 110882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 110982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 111082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 111182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 111282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 111382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 111482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 11157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 111682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 11177ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final Account selectedAccount = sendOrSaveMessage.mSelectedAccount; 11187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 11197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 112082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 112182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 112282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 11237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) { 112482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 112582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 112682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 112782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 1128cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira if (selectedAccount.expungeMessageUri != null) { 1129cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira resolver.update(selectedAccount.expungeMessageUri, values, null, 1130eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira null); 1131cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1132cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 1133eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 113482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 113582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 113682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 113782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 113882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 113982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 114082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) { 11417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 114282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext.getContentResolver().update( 11437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri), 11447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues, null, null); 114582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } else { 11467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira ContentResolver resolver = mContext.getContentResolver(); 11477ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Uri messageUri = resolver.insert( 1148cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira sendOrSaveMessage.mSave ? selectedAccount.saveDraftUri 1149cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira : selectedAccount.sendMessageUri, sendOrSaveMessage.mValues); 11507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sendOrSaveMessage.mSave && messageUri != null) { 11517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Cursor messageCursor = resolver.query(messageUri, 11527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira UIProvider.MESSAGE_PROJECTION, null, null, null); 1153ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor != null) { 1154ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 1155ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor.moveToFirst()) { 1156ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // Broadcast notification that a new message has 1157ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // been allocated 1158ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 1159ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook new Message(messageCursor)); 1160ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 1161ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } finally { 1162ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook messageCursor.close(); 1163ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 11647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 11657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 116682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 116782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 11687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!sendOrSaveMessage.mSave) { 116982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 11707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 117182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 11727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 117382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 11747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 117582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 117682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 117782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 117882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 117982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 118082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Array of the outstanding send or save tasks. Access is synchronized 118182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // with the object itself 118282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /* package for testing */ 118382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 118482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRequestId; 1185bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String mSignature; 118682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 118782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ static class SendOrSaveMessage { 118882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final Account mAccount; 118982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final Account mSelectedAccount; 119082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 11913ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 119282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final boolean mSave; 119382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 119482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 119582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveMessage(Account account, Account selectedAccount, ContentValues values, 11963ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String refMessageId, boolean save) { 119782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 119882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSelectedAccount = selectedAccount; 119982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 120082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 120182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 120282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 120382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 120482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 120582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 120682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 120782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 120882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 120982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 121082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 121182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 121282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 121382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 121482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 121582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 121682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 121782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 121882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 121982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 122082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 122182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 122282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 122382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 122482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 122582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 122682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 122782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 122882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 122982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 123082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 123182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 123282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 123382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 123482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 123582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 123682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 123782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 123882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 123982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 124082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 124182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 124282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 124382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 124482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 124582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 124682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 124782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 124882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 124982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) { 125082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (String email : to) { 125182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 125282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 125382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 125482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 125582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 125682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 125782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 125882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 125982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 126082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 126182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void showRecipientErrorDialog(String message) { 126282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Only 1 invalid recipients error dialog should be allowed up at a 126382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // time. 126482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mRecipientErrorDialog != null) { 126582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog.dismiss(); 126682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 126782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle( 126882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.recipient_error_dialog_title) 126982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 127082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setCancelable(false) 127182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setPositiveButton( 127282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.ok, new Dialog.OnClickListener() { 127382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 127482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // after the user dismisses the recipient error 127582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // dialog we want to make sure to refocus the 127682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // recipient to field so they can fix the issue 127782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // easily 127882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mTo != null) { 127982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTo.requestFocus(); 128082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 128182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = null; 128282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 128382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira }).show(); 128482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 128582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 128682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 128782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 128882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 128982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 1290eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 129182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 129282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 129382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 129482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 129582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 129682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 129782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 129882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 129982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 13007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 130182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 130282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 130382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 130482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 1305eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return (mTextChanged || mAttachmentsChanged || 130682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira (mReplyFromChanged && !isBlank())); 130782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 130882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 130982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 131082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1311bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 131282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 131382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 131482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 131582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 1316bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 1317bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 1318bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 1319bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 1320bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 1321bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1322bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1323bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 1324bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 1325bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 1326bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1327bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 1328bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 1329bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1330bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1331bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 1332bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 1333bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 1334bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 1335bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1336bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 1337bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 1338bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 1339bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 1340bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 1341bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 1342bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 1343bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 1344bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1345bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 134682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 134782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 134882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 134982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 135082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 135182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 135282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 135382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 1354eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 135582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 135633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 135733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 135882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1359181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param body 1360181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 1361181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 1362181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 1363181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1364181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 1365181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira final boolean orientationChanged) { 1366181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1367181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Editable body = mBodyView.getEditableText(); 1368181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1369181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1370181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1371181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1372181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1373181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1374181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1375181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1376181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1377181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 1378181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 1379181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 1380181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 1381181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1382181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1383181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1384181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 1385181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1386181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 1387181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 1388181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 1389181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1390181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1391181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 1392181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 1393181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 1394181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 1395181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 1396181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1397181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1398181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1399181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 1400181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onClick(DialogInterface dialog, int which) { 1401181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged); 1402181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1403181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1404181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1405181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 1406181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1407181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 1408181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 1409181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean emptyBody = TextUtils.getTrimmedLength(body) == 0; 1410181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1411181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 1412181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 1413181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 1414181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 1415181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1416181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 1417181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 1418181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 1419181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 1420181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener); 1421181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1422181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1423181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1424181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 1425181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener); 1426181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1427181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1428181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1429181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 1430181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 1431181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message, listener); 1432181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1433181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1434181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1435181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1436181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(body, save, showToast, false); 1437181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1438181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1439181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1440181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1441181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 1442181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 1443181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1444181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 1445181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1446181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 1447181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 1448181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1449181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1450181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1451181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 1452181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1453181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 1454181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1455181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 1456181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 1457181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1458181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1459181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) { 1460181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendConfirmDialog != null) { 1461181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog.dismiss(); 1462181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = null; 1463181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1464181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId) 1465181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setTitle(R.string.confirm_send_title) 1466181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 1467181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setPositiveButton(R.string.send, listener) 1468181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setNegativeButton(R.string.cancel, this).setCancelable(false).show(); 1469181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1470181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1471181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1472181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 1473181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 1474181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 1475181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1476181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 1477181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 1478181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1479181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1480181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1481181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 1482181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1483181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 1484181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 1486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 1487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 1488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 1489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 149229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira static int sendOrSaveInternal(Context context, final Account account, 149329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira final Account selectedAccount, String fromAddress, final Spanned body, 149429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira final String[] to, final String[] cc, final String[] bcc, final String subject, 149529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira final CharSequence quotedText, final List<Attachment> attachments, 14963ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String refMessageId, SendOrSaveCallback callback, Handler handler, boolean save, 149712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira int composeMode) { 149829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira ContentValues values = new ContentValues(); 149929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 150029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putToAddresses(values, to); 150129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putCcAddresses(values, cc); 150229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putBccAddresses(values, bcc); 150329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 150429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putSubject(values, subject); 150529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira String htmlBody = Html.toHtml(body); 150629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 150729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 150829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 1509e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 1510e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 1511e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 1512e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 1513e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text.substring(0, pos)); 1514e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putQuoteStartPos(values, pos); 151512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 1516e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 151729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 1518e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 1519e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 1520e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 1521e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 152229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 152329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 152412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira int draftType = -1; 152512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira switch (composeMode) { 152612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.COMPOSE: 152712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.COMPOSE; 152812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 152912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.REPLY: 153012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.REPLY; 153112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 153212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.REPLY_ALL: 153312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.REPLY_ALL; 153412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 153512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.FORWARD: 153612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.FORWARD; 153712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 153812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 153912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 154029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 154129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1542f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira MessageModification.putAttachments(values, attachments); 154312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 154412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 154512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 154682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1547181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(account, selectedAccount, 1548181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira values, refMessageId, save); 1549181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback); 155082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1551181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 155282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 1554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 1555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 155682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 1558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 155982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void sendOrSave(Spanned body, boolean save, boolean showToast, 1561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean orientationChanged) { 1562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 1563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 1564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && ActivityManager.isUserAMonkey()) { 1565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 1566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 156782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 157682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 157882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 157982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 158082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 1581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 1582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 1583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 1584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 1585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 1586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 1587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 1590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 1592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 1593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 159582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 15967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 15977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 1598181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 1599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 1600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 16017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 16027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 16037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 1604181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 1605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 1606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 16087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 1609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1610181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 161182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 16127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 16137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 16147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 16157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 16167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 161782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 16187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 16197ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 16207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 16217ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 16227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 16237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 16247ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 16257ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 16267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 16277ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 16287ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 162982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 16307ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 16317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 16327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 16337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 16347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 16357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 163682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 16377ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 16387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 16397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 16407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 16417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 16427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 16437ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 16447ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 1645181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1646181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1647181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Get the selected account if the from spinner has been setup. 1648181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Account selectedAccount = mAccount; 1649181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String fromAddress = selectedAccount.name; 1650181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (selectedAccount == null || fromAddress == null) { 1651181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // We don't have either the selected account or from address, 1652181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // use mAccount. 1653181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira selectedAccount = mAccount; 1654181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira fromAddress = mAccount.name; 1655181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1656181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1657181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 1658181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 1659181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 1660181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1661181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 1662181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1663181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 166412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira String refMessageString = mRefMessage != null ? mRefMessage.uri.toString() : ""; 1665181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRequestId = sendOrSaveInternal(this, mAccount, selectedAccount, fromAddress, body, to, cc, 1666181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc, mSubject.getText().toString(), mQuotedTextView.getQuotedText(), 166712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira mAttachmentsView.getAttachments(), refMessageString, callback, 166812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira mSendSaveTaskHandler, save, mComposeMode); 1669181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1670181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mRecipient != null && mRecipient.equals(mAccount.name)) { 1671181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRecipient = selectedAccount.name; 1672181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1673181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mAccount = selectedAccount; 1674181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1675181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 1676181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 1677181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 1678181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 1679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 1680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 1681181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1682181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 1684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 1685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 1686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 1687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 1689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 1691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 1696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 1697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 1698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 1700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 1701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 170282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1703013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void doAttach() { 1704013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 1705013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 1706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (android.provider.Settings.System.getInt(getContentResolver(), 1707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira UIProvider.getAttachmentTypeSetting(), 0) != 0) { 1708013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.setType("*/*"); 1709013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } else { 1710013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.setType("image/*"); 1711013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1712013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 1713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 1714181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 1715013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1716013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 1717ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 1718a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 1719ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1720ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 1721ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1722ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1723ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1724326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 1725326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 1726a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 1727326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 1728326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 1729326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 1730326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 1731326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 1732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 1733326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1734a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 1735154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 17368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (mRefMessage != null) { 17378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromRefMessage(mComposeMode, mAccount.name); 17388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1739a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 1740326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 1741326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1742326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1743154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira private void resetMessageForModeChange() { 1744154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 1745154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 1746154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 1747154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 1748154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 1749154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 1750154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 1751154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 1752154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 1753154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 1754154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 1755154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 1756154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 1757154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 1758154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 1759154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 1760154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 1761154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 1762154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 1763154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 1764154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 1765154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 1766326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 1767326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1768326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 1769326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1770326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 1771326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 1772326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 1773326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1774326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1775326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 1776326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 1777326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 1778326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1779326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 1780326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1781326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1782326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 1783326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 1784326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 1785326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 1786326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1787326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 1788326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 1789326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1790326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 179146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 179246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 179346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 179446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 179546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 179646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 179746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 179846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 179946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 180046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 180146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 180246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 180346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 180446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 1805eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 180646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 180746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 180846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 180946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 181046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 181146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 181246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 181346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 181446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 1815bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 181646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 181746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 181846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 181946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 1820eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 1821bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 1822bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 1823bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1824bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1825bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1826bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 1827bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mSignature = mCachedSettings != null ? mCachedSettings.signature : null; 1828bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (!TextUtils.isEmpty(mSignature)) { 1829bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira // Appending a signature does not count as changing text. 1830bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.removeTextChangedListener(this); 1831bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 1832bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.addTextChangedListener(this); 1833bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1834bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1835bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1836bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 1837bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 1838bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 1839bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 1840bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1841bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 184246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 18431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 18445a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 18455a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 18465a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira Account selectedAccountInfo = mFromSpinner.getCurrentAccount(); 1847181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!mAccount.equals(selectedAccountInfo)) { 1848181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mAccount = selectedAccountInfo; 1849181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mCachedSettings = null; 1850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira getLoaderManager().restartLoader(ACCOUNT_SETTINGS_LOADER, null, this); 1851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 1852181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 1853181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 1854181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 1855181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 1856181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1857181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 1858181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 185982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 18601a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 186182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 186282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 186382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 186482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 186582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 186682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 186782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 186882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSend(boolean enabled) { 186982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSend != null) { 187082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend.setEnabled(enabled); 187182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 187282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 187382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 187482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Handles button clicks from any error dialogs dealing with sending 187682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * a message. 187782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 187882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 187982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 188082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira switch (which) { 188182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_POSITIVE: { 188282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira doDiscardWithoutConfirmation(true /* show toast */ ); 188382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 188482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 188582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_NEGATIVE: { 188682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If the user cancels the send, re-enable the send button. 188782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira enableSend(true); 188882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 188982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 189082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 189182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 189282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 189382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1894efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 1895efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text) 1896efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setPositiveButton(R.string.ok, this) 1897efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setNegativeButton(R.string.cancel, null) 1898efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .create().show(); 1899efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 190082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 190182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 190282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 190382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 190482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 190582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param showToast show "Message discarded" toast if true 190682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 190782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void doDiscardWithoutConfirmation(boolean showToast) { 19087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 190982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 191082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 1911b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 1912cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira if (mAccount.expungeMessageUri != null) { 1913cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 1914cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1915cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp): call delete on this conversation instead. 1916cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 191782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 191882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 191982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 192082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 192182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 192282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 192382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 192482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 192582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (showToast) { 192682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Display a toast to let the user know 192782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 192882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 192982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 193082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 193182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 193282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 193382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 193482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1935eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 1936eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 1937eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 1938eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 1939eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 1940eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 1941eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1942eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1943eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 1944eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSave(!mAddingAttachment /* show toast */, true /* reset IME */); 1945eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1946eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1947eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1948eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeededOnOrientationChanged() { 1949eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 1950eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 1951eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 1952eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 1953eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 1954eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1955eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1956eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 1957eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSaveOrientationChanged(!mAddingAttachment /* show toast */, true /* reset IME */); 1958eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1959eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1960eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1961eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira /** 1962eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira * Save a draft if a draft already exists or the message is not empty. 1963eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira */ 1964eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void doSaveOrientationChanged(boolean showToast, boolean resetIME) { 1965eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveOnOrientationChanged(); 1966eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (resetIME) { 1967eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // Clear the IME composing suggestions from the body. 1968eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira BaseInputConnection.removeComposingSpans(mBodyView.getEditableText()); 1969eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1970eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1971eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1972eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected boolean saveOnOrientationChanged() { 1973eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return sendOrSaveWithSanityChecks(true, false, true); 1974eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1975eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1976eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 1977eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 1978eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 1979eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 1980eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 198175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 198275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 198375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 198475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 198575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 198675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 198775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 198875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 198975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 199075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 199175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 199275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 199375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 199475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 199575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 199675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 199775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 199875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 199975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 200075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 200175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 200275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 200375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 200475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 200575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 200675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 200775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 200875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 200975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 201075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 201175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 201275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 201375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 201475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 201575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 201675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 201775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 201875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 201975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 202075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 202175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 202275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 202375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 202475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 202575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 202675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 202775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 202875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 202975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 203075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 203175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 203275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 203375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 203475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 203575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 203675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 203775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 203875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 203975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 204075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 204175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 204275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 204375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 204475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 204575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 204675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 204775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 204875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 204975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 205075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 205175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 205275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 205375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 205475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 205575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 205675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 205775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 205875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 205975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 206075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 206175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 206275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 206375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 206475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 206575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 206675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 206775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 206875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 206975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 207075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 207175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 207275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 207375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 207475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 2075181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2076181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira @Override 2077181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public Loader<Cursor> onCreateLoader(int id, Bundle args) { 2078181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (id == ACCOUNT_SETTINGS_LOADER) { 207923e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (mAccount != null && mAccount.settingsQueryUri != null) { 2080181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return new CursorLoader(this, mAccount.settingsQueryUri, 2081181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira UIProvider.SETTINGS_PROJECTION, null, null, null); 2082181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2083181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2084181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return null; 2085181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2086181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2087181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira @Override 2088181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 2089181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (loader.getId() == ACCOUNT_SETTINGS_LOADER) { 2090181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (data != null) { 2091181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira data.moveToFirst(); 2092181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mCachedSettings = new Settings(data); 2093bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 2094181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2095181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2096181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2097181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2098181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira @Override 2099181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onLoaderReset(Loader<Cursor> loader) { 2100181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do nothing. 2101181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 21028e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira}