ComposeActivity.java revision 2ea06183aa826b28fe6ebdb454da49ba3878bc4f
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/** 28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc. 38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License. 68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at 78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software 118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and 148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License. 158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */ 168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose; 188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar; 205c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.ActionBar.OnNavigationListener; 215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.app.Activity; 2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager; 2382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog; 2482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog; 256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver; 2682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues; 276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context; 2882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface; 296349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent; 3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo; 317ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor; 326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri; 338e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle; 3482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler; 3582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread; 36f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable; 3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns; 3846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable; 3982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html; 4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned; 41c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils; 4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher; 4346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token; 44c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 45326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater; 46b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu; 47b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater; 48b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem; 498e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View; 508e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener; 512ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sappersteinimport android.view.View.OnFocusChangeListener; 525c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup; 53eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection; 54326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 558e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 56433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText; 571f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView; 586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 59013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 607b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 61c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView; 635c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R; 64eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener; 659932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 665a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 6730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 6833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 7030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 713ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 7282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 7392551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount; 74181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 7530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 763ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 7712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 7892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 8146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 8282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 848e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 8562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException; 8662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 8946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 90bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 9146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 9275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 9346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 9446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 951c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 96bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 9782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 9846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 9946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 1005a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira RespondInlineListener, DialogInterface.OnClickListener, TextWatcher, 1012ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein AttachmentDeletedListener, OnAccountChangedListener, OnFocusChangeListener { 1026349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 10336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int COMPOSE = -1; 10436bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int REPLY = 0; 10536bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int REPLY_ALL = 1; 10636bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int FORWARD = 2; 10736bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int EDIT_DRAFT = 3; 1086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1096349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 11036bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_ACTION = "action"; 1116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 112326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_CC = "showCc"; 113326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_BCC = "showBcc"; 114a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira 1158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1239a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira private static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString"; 1249a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_TO = "to"; 1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 1318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC }; 1328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 14382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 14482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 14582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 14682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Key used to store the above map 14782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids"; 1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 154daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook public static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 156e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String EXTRA_ATTACHMENTS = "attachments"; 157f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1583ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 15936bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 160bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // If this is an action to edit an existing draft messagge, this extra will hold the 161bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 162bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 1634a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 164013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final String LOG_TAG = new LogUtils().getLogTag(); 165013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 166013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 167013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 169e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 1708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Max size for attachments (5 megs). Will be overridden by account settings if found. 1728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp): read this from account settings? 1738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024; 174e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount"; 175e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_REQUEST_ID = "requestId"; 176e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart"; 177e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_END = null; 178e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_MESSAGE = "extraMessage"; 1798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 18182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 18282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 18382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 184c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 185c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 186c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 1878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 1888e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 1897b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 19033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private Account mAccount; 19192551d057965689f1952faeb06763f0762bc717fMindy Pereira private ReplyFromAccount mReplyFromAccount; 192181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 19382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 1946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 1956349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 196326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 197326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private int mComposeMode = -1; 19846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 19946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private String mRecipient; 20046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 201433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private EditText mBodyView; 2021a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 2032eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 204eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 2055a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira private FromAddressSpinner mFromSpinner; 206013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 207eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 20882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 20982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 21082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 21182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 21282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private AlertDialog mRecipientErrorDialog; 213eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private AlertDialog mSendConfirmDialog; 2143ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private Message mRefMessage; 2157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 2177ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 2181f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira private ImageView mAttachmentsButton; 2193ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 220326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 221daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook * Boolean indicating whether ComposeActivity was launched from a Gmail controlled view. 222daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook */ 223daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private boolean mLaunchedFromEmail = false; 224daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 225daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 226daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook /** 227326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 228326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 2293ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 230bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook launch(launcher, account, message, EDIT_DRAFT); 231326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 23633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 2376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launch(launcher, account, null, COMPOSE); 2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2426349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 2443ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY); 2456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2503ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 2513ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY_ALL); 2526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2573ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 2583ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, FORWARD); 2596349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2613ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static void launch(Context launcher, Account account, Message message, int action) { 2626349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 2636349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 2646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 2656349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 266bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 267bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 268bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 269bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 270bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 2716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 2726349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2738e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 2748e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 2758e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onCreate(Bundle savedInstanceState) { 2768e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 2778e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 27846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 2792ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein setFocusListeners(); 280818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 281e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira Account account = null; 282e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message; 28371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira boolean showQuotedText = false; 284e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int action; 285e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira Object accountExtra = intent != null && intent.getExtras() != null ? intent.getExtras() 286e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira .get(Utils.EXTRA_ACCOUNT) : null; 287e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this); 288f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira if (hadSavedInstanceStateMessage(savedInstanceState)) { 289e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE); 290e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT); 291e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE); 292e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE); 293e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 294e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (accountExtra instanceof Account) { 295e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira account = (Account) intent.getExtras().get(Utils.EXTRA_ACCOUNT); 296e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } else if (accountExtra instanceof String) { 297e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira // For backwards compatibility 298e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira String extraAccount = intent.getStringExtra(Utils.EXTRA_ACCOUNT); 299e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (syncingAccounts.length > 0) { 300e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (!TextUtils.isEmpty(extraAccount)) { 301e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira for (Account a : syncingAccounts) { 302e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (a.name.equals(extraAccount)) { 303e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira account = a; 304e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 305e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 306e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 307e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 308e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 309e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 310e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // Initialize the message from the message in the intent 311e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 312e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 313e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 31492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (account == null) { 315e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (syncingAccounts != null && syncingAccounts.length > 0) { 316e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira account = syncingAccounts[0]; 31792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 31892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 31992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 32092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 321818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 322818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 323818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 324bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 325daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (intent.getBooleanExtra(EXTRA_FROM_EMAIL_TASK, false)) { 326daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = true; 327daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } else if (Intent.ACTION_SEND.equals(intent.getAction())) { 328daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final Uri dataUri = intent.getData(); 329daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (dataUri != null) { 330daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String dataScheme = intent.getData().getScheme(); 331daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final String accountScheme = mAccount.composeIntentUri.getScheme(); 332daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mLaunchedFromEmail = TextUtils.equals(dataScheme, accountScheme); 333daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 334daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 335daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 336e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (message != null && action != EDIT_DRAFT) { 337e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 338e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 339a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira showCcBcc(savedInstanceState); 34071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = message.appendRefMessageContent; 341e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (action == EDIT_DRAFT) { 342e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 343ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showBcc = !TextUtils.isEmpty(message.bcc); 344ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showCc = showBcc || !TextUtils.isEmpty(message.cc); 345ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 346bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 347bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 348bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 349bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 350bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 351bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 352bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 353bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 354bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 355bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 356bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 357bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 358bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 359bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 360bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 361bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 362e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 36371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = message.appendRefMessageContent; 364e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 365e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 366e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromRefMessage(action, mAccount.name); 367ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mRefMessage != null) { 368ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // CC field only gets populated when doing REPLY_ALL. 369ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // BCC never gets auto-populated, unless the user is editing 370ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // a draft with one. 371ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (!TextUtils.isEmpty(mRefMessage.cc) && action == REPLY_ALL) { 372ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, true, false); 373ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } 374ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } 375ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira updateHideOrShowCcBcc(); 37671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = true; 377e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 3788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 3798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromExtras(intent); 380bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 381bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 382bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == COMPOSE) { 383eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mQuotedTextView.setVisibility(View.GONE); 38446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 385818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira initRecipients(); 386f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // Don't bother with the intent if we have procured a message from the 387f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira // intent already. 388f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira if (!hadSavedInstanceStateMessage(savedInstanceState)) { 389f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira initAttachmentsFromIntent(intent); 390f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 3911a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira initActionBar(action); 392e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(), 393e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action); 39475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 395433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira setFocus(action); 396326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira updateHideOrShowCcBcc(); 39771c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira updateHideOrShowQuotedText(showQuotedText); 39871c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira } 39971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira 400f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira private boolean hadSavedInstanceStateMessage(Bundle savedInstanceState) { 401f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira return savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE); 402f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira } 403f7fc6c339da7f73755041cceb9b8f8447680728aMindy Pereira 40471c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira private void updateHideOrShowQuotedText(boolean showQuotedText) { 40571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira mQuotedTextView.updateCheckedState(showQuotedText); 406433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 407433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 408433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private void setFocus(int action) { 409433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (action == EDIT_DRAFT) { 410433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int type = mDraft.draftType; 411433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (type) { 412433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.COMPOSE: 413433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.FORWARD: 414433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = COMPOSE; 415433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 416433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY: 417433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY_ALL: 418433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 419433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = REPLY; 420433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 421433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 422433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 423433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (action) { 424433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case FORWARD: 425433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case COMPOSE: 426433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mTo.requestFocus(); 427433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 428433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY: 429433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY_ALL: 430433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 431433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 432433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 433433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 434433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 435433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 436433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira /** 437433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira * Focus the body of the message. 438433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira */ 439433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira public void focusBody() { 440433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.requestFocus(); 441433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int length = mBodyView.getText().length(); 442433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 443433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int signatureStartPos = getSignatureStartPosition( 444433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mSignature, mBodyView.getText().toString()); 445433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (signatureStartPos > -1) { 446433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // In case the user deleted the newlines... 447433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(signatureStartPos); 448433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } else if (length > 0) { 449433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // Move cursor to the end. 450433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(length); 451433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 4521a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 4531a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 4541a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 4551a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 4561a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 4571a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 4581a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 459818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 46062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount); 461818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 4621a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 4631a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 464eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 465eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 466eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 467eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 468eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mSendConfirmDialog != null) { 469eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mSendConfirmDialog.dismiss(); 470eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 471eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mRecipientErrorDialog != null) { 472eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mRecipientErrorDialog.dismiss(); 473eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 474eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveIfNeeded(); 475eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 476eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 477eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 478eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 479eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAddingAttachment = false; 480eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 481eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) { 482eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 483eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 484eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 485eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 486eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 487e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira public final void onRestoreInstanceState(Bundle savedInstanceState) { 488e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira super.onRestoreInstanceState(savedInstanceState); 489e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState != null) { 490e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) { 491e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START); 492e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END); 493e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // There should be a focus and it should be an EditText since we 494e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // only save these extras if these conditions are true. 495e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) getCurrentFocus(); 496e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira final int length = focusEditText.getText().length(); 497e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectionStart < length && selectionEnd < length) { 498e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira focusEditText.setSelection(selectionStart, selectionEnd); 499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 500e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 501e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 502e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 503e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 504e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira @Override 505eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public final void onSaveInstanceState(Bundle state) { 506eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 507e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // The framework is happy to save and restore the selection but only if it also saves and 508e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // restores the contents of the edit text. That's a lot of text to put in a bundle so we do 509e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // this manually. 510e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira View focus = getCurrentFocus(); 511e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (focus != null && focus instanceof EditText) { 512e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) focus; 513e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart()); 514e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd()); 515e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 5166273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook 5176273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 518151f1ad1613ecac0207144472872440517172b5aPaul Westbrook final int selectedPos = mFromSpinner.getSelectedItemPosition(); 5196273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final ReplyFromAccount selectedReplyFromAccount = 520151f1ad1613ecac0207144472872440517172b5aPaul Westbrook (replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ? 521151f1ad1613ecac0207144472872440517172b5aPaul Westbrook replyFromAccounts.get(selectedPos) : 5226273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook null; 523e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectedReplyFromAccount != null) { 524e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize() 525e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .toString()); 526e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account); 527e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 528e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount); 529e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 530eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 531e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) { 532e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We don't have a draft id, and we have a request id, 533e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // save the request id. 534e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_REQUEST_ID, mRequestId); 535e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 536e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 537e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We want to restore the current mode after a pause 538e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // or rotation. 539e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = getMode(); 540e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_ACTION, mode); 541e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 542e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = createMessage(selectedReplyFromAccount, mode); 543e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_MESSAGE, message); 544e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 545e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 546e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage); 547e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 548326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible()); 549326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible()); 550e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 551e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 552e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private int getMode() { 553e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = ComposeActivity.COMPOSE; 554e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ActionBar actionBar = getActionBar(); 555e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar != null 556e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira && actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) { 557e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mode = actionBar.getSelectedNavigationIndex(); 558e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 559e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return mode; 560e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 561e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 562e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) { 563e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = new Message(); 564e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.id = UIProvider.INVALID_MESSAGE_ID; 565e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.serverId =UIProvider.INVALID_MESSAGE_ID; 566e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.uri = null; 567e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.conversationUri = null; 568e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.subject = mSubject.getText().toString(); 569e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.snippet = null; 57091906814d08fe6bcfcd97f25f5a01d36d9d5dc73Paul Westbrook message.from = selectedReplyFromAccount != null ? 57191906814d08fe6bcfcd97f25f5a01d36d9d5dc73Paul Westbrook selectedReplyFromAccount.name : mAccount.name; 572e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.to = mTo.getText().toString(); 5734b1377e9f7677671eda0d5508a0603ec7433d19dMindy Pereira message.cc = mCc.getText().toString(); 5744b1377e9f7677671eda0d5508a0603ec7433d19dMindy Pereira message.bcc = mBcc.getText().toString(); 575e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.replyTo = null; 576e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.dateReceivedMs = 0; 577e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira String htmlBody = Html.toHtml(mBodyView.getText()); 578e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 579e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyHtml = fullBody.toString(); 580e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyText = mBodyView.getText().toString(); 581e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.embedsExternalResources = false; 582e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null; 583d2bef8b371784d95f60dd3f89aa0ac3557c945efMindy Pereira message.draftType = getDraftType(mode); 584e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null; 585e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ArrayList<Attachment> attachments = mAttachmentsView.getAttachments(); 586e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.hasAttachments = attachments != null && attachments.size() > 0; 587e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentListUri = null; 588e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.messageFlags = 0; 589e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.saveUri = null; 590e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.sendUri = null; 591e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.alwaysShowImages = false; 592e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentsJson = Attachment.toJSONArray(attachments); 593e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira CharSequence quotedText = mQuotedTextView.getQuotedText(); 594e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView 595e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .getQuotedTextOffset(quotedText.toString()) : -1; 596e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.accountUri = null; 597e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return message; 598eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 599eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 600818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 601818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 602bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira if (account == null) { 603bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira return; 604bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira } 60523e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 60623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 607b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook mCachedSettings = mAccount.settings; 608b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook appendSignature(); 60923e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 610818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 611818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 612e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromSpinner(Bundle bundle, int action) { 6139a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira String accountString = null; 614e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) { 61562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira action = COMPOSE; 61662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 61762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.asyncInitFromSpinner(action, mAccount); 6189a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle != null) { 6199a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) { 6209a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = ReplyFromAccount.deserialize(mAccount, 6219a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)); 6229a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) { 6239a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING); 6249a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString); 6259a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } 626e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 627e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mReplyFromAccount == null) { 628e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraft != null) { 629e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft); 630e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (mRefMessage != null) { 631e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage); 632e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 63362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 63462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mReplyFromAccount == null) { 63562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 636cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira mAccount.name, mAccount.name, true, false); 63762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 6389a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 63962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.setCurrentAccount(mReplyFromAccount); 6409a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 64162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mFromSpinner.getCount() > 1) { 642a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // If there is only 1 account, just show that account. 643a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // Otherwise, give the user the ability to choose which account to 64462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // send mail from / save drafts to. 64562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromStatic.setVisibility(View.GONE); 646a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 64762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinnerWrapper.setVisibility(View.VISIBLE); 648a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } else { 649a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStatic.setVisibility(View.VISIBLE); 650a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 651a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromSpinnerWrapper.setVisibility(View.GONE); 652a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } 65346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 65446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 65562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) { 65662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (refMessage.accountUri != null) { 65762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // This must be from combined inbox. 65862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 65962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 66062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.account.uri.equals(refMessage.accountUri)) { 66162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 66262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return null; 66562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 66662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getReplyFromAccount(account, refMessage); 66762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 67062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 67162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Given an account and which email address the message was sent to, 67262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * return who the message should be sent from. 67362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param account Account in which the message arrived. 67462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param sentTo Email address to which the message was sent. 67562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @return the address from which to reply. 67662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 67762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) { 67862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // First see if we are supposed to use the default address or 67962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // the address it was sentTo. 680326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (mCachedSettings.forceReplyFromDefault) { 68162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getDefaultReplyFromAccount(account); 68262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 68389bae5713b830ec1182073de22c3091d3613ac3eMindy Pereira // If we aren't explicitly told which account to look for, look at 68462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // all the message recipients and find one that matches 68562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // a custom from or account. 68662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<String> allRecipients = new ArrayList<String>(); 68762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to))); 68862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc))); 68962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getMatchingRecipient(account, allRecipients); 69062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 69162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 69262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 69362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 69462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Compare all the recipients of an email to the current account and all 69562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * custom addresses associated with that account. Return the match if there 69662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * is one, or the default account if there isn't. 69762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 69862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) { 69962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // Tokenize the list and place in a hashmap. 70062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount matchingReplyFrom = null; 70162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira Rfc822Token[] tokens; 70262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira HashSet<String> recipientsMap = new HashSet<String>(); 70362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (String address : sentTo) { 70462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira tokens = Rfc822Tokenizer.tokenize(address); 70562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (int i = 0; i < tokens.length; i++) { 70662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira recipientsMap.add(tokens[i].getAddress()); 70762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 70862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 70962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 71062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira int matchingAddressCount = 0; 71162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> customFroms; 71262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira try { 71362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira customFroms = FromAddressSpinner.getAccountSpecificFroms(account); 71462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (customFroms != null) { 71562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount entry : customFroms) { 71662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (recipientsMap.contains(entry.address)) { 71762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = entry; 71862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingAddressCount++; 71962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 72062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 72162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 72262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } catch (JSONException e) { 72362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s", 72462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira account.name); 72562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 72662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (matchingAddressCount > 1) { 72762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = getDefaultReplyFromAccount(account); 72862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 72962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return matchingReplyFrom; 73062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 73162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 73262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getDefaultReplyFromAccount(Account account) { 73362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 73462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 73562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.isDefault) { 73662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 73762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 73862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 739cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira return new ReplyFromAccount(account, account.uri, account.name, account.name, account.name, 740cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira true, false); 74162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 74262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 743e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) { 744e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira String sender = msg.from; 74562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount replyFromAccount = null; 74662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 74762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(account.name, sender)) { 74862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 749cd970ddaba4e212b668588db2104dc46ad3ad793Mindy Pereira mAccount.name, mAccount.name, true, false); 75062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 75162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount fromAccount : replyFromAccounts) { 75262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(fromAccount.name, sender)) { 75362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = fromAccount; 75462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira break; 75562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 75662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 75762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 75862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return replyFromAccount; 75962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 76062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 76146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 762a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 7638e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 7648e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 7658e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 7668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 7677b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 7681f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment); 7691f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira if (mAttachmentsButton != null) { 7701f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton.setOnClickListener(this); 7711f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira } 772818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 773818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 774818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 77582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 77682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 7776349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 77846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 77946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 780433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView = (EditText) findViewById(R.id.body); 7811a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 7822eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 783eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 7845a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 785326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 786326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 7872ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein private void setFocusListeners() { 7882ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mTo.setOnFocusChangeListener(this); 7892ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mCc.setOnFocusChangeListener(this); 7902ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mBcc.setOnFocusChangeListener(this); 7912ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mSubject.setOnFocusChangeListener(this); 7922ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mQuotedTextView.setOnFocusChangeListener(this); 7932ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mBodyView.setOnFocusChangeListener(this); 7942ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein } 7952ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein 7962ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein @Override 7972ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein public void onFocusChange(View v, boolean hasFocus) { 7982ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein if (hasFocus) { 7992ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein mAttachmentsView.collapseView(); 8002ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein } 8012ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein } 8022ea06183aa826b28fe6ebdb454da49ba3878bc4fAndrew Sapperstein 803e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira protected TextView getBody() { 804e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mBodyView; 805e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 806e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 807e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 808e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public Account getFromAccount() { 809e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return mReplyFromAccount != null && mReplyFromAccount.account != null ? 810e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira mReplyFromAccount.account : mAccount; 811e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 812e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 81375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 81475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 81575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 81675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 81775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 81875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 81975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this)); 82075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this)); 82175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this)); 82275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 823818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 82475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 82575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 826326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private void initActionBar(int action) { 827326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = action; 828eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 829e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (actionBar == null) { 830e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira return; 831e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 832326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (action == ComposeActivity.COMPOSE) { 833eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 834eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 835326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 836eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 837326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 838326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 839326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 840eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 841eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 842326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira switch (action) { 843326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 844eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 845326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 846326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 847eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 848326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 849326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 850eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 851326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 852326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 8536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 854fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 855fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 856fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 8576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 8586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 85946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void initFromRefMessage(int action, String recipientAddress) { 8608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 8618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 8628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 8638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 8648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initRecipientsFromRefMessage(recipientAddress, mRefMessage, action); 866e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 8678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 8688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 8696349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 870c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 871c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 872e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromDraftMessage(Message message) { 873bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook LogUtils.d(LOG_TAG, "Intializing draft from previous draft message"); 874bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 875bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 876bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 877bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 878bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 879bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final List<String> toAddresses = Arrays.asList(message.getToAddresses()); 880bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 881bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses); 882bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addBccAddresses(Arrays.asList(message.getBccAddresses())); 8832421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (message.hasAttachments) { 8842421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira List<Attachment> attachments = message.getAttachments(); 8852421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira for (Attachment a : attachments) { 8865c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(a); 8872421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 8882421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 889cc8e7db940b2ad6c673e84ca7addae9295c10a33Mindy Pereira int quotedTextIndex = message.appendRefMessageContent ? 890002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.quotedTextOffset : -1; 891bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 892002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence quotedText = null; 893bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 894002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence htmlText = Html.fromHtml(message.bodyHtml); 895002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 896002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira htmlText = htmlText.subSequence(0, quotedTextIndex); 897002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira quotedText = message.bodyHtml.subSequence(quotedTextIndex, 898002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.bodyHtml.length()); 899002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 900002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(htmlText); 901bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 902002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence bodyText = quotedTextIndex > -1 ? 903002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.bodyText.substring(0, quotedTextIndex) : message.bodyText; 904002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 905002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira quotedText = message.bodyText.substring(quotedTextIndex); 906002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 907002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(bodyText); 908002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 909002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1 && quotedText != null) { 9103971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward); 911bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 912bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 913bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 9148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 9158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 9168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 9178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 9188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 9198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 9208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 9218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 9228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 9238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 9248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromExtras(Intent intent) { 9258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 9268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 9278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 9288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 9298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 9308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 9318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 9320b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira if (!mAccount.composeIntentUri.equals(dataUri)) { 9338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 9348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 9358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 936dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(toText, ","))); 9378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 9438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 9448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 9458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 9478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 9488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 9498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 9518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 9528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 9538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 9568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 9578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 9588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 9618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 9628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 9638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 964dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(value, ","))); 9658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 966dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null); 9678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 968dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addBccAddresses(Arrays.asList(TextUtils.split(value, ","))); 9698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 9708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 9718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 9728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 9738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 9788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 9798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 9808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 9818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 9828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 984e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 985e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 9868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 9878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 988a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // TODO: handle the case where there are spaces in the display name as 989a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // well as the email such as "Guy with spaces <guy+with+spaces@gmail.com>" 990a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira // as they could be encoded ambiguously. 9918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 9928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 9938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 9948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String replacePlus = s.replace("+", "%2B"); 995a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira try { 996a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME); 997a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } catch (IllegalArgumentException e) { 998a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 999a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), s); 1000a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } else { 1001a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 1002a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 1003a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira return null; 1004a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 10058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 10088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 10098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 10108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 10118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 10128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 10138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 10148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 10158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 10168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 10178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 10188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 10198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 10208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 10218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 10228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 10238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 10248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1025a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira if (!TextUtils.isEmpty(to)) { 1026a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira addToAddresses(Arrays.asList(TextUtils.split(to, ","))); 1027a4069f2f16c05c6d2948baa39b0c463be4c7a360Mindy Pereira } 10288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 10298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 10308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 10318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 10328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 10338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 10378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 10388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 10408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 10418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 10438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 10448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 10468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 10478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 10488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME)); 10498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 10508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 10518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 10528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 10568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 10578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 10588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME), 10598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 10608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 10618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 10628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 10663ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void initAttachments(Message refMessage) { 10677a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira mAttachmentsView.addAttachments(mAccount, refMessage); 1068eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1069eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1070f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 107103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook Bundle extras = intent.getExtras(); 107203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook if (extras == null) { 107303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook extras = Bundle.EMPTY; 107403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook } 1075f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 1076f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 1077f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 1078f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 1079f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 1080f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 1081f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 1082f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1083f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 10845c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 1085f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1086f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 1087f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 1088f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1089f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1090f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1091f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1092f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1093f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) { 1094f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 1095f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1096f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 10975c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 1098f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1099f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, so just 1100f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // exit. 1101f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1102f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1103f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1104f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1105f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1106f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND_MULTIPLE.equals(action) 1107f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook && extras.containsKey(Intent.EXTRA_STREAM)) { 1108f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); 1109f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (Parcelable uri : uris) { 1110f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1111f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 11125c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, (Uri) uri); 1113f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1114f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 1115f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 1116f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1117f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1118f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1119f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1120f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1121f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1122f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 1123f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 1124f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 1125f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1126f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1127f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1128f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1129f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1130e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initQuotedTextFromRefMessage(Message refMessage, int action) { 1131e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) { 11329932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 11339932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 113446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 113546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 113646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 1137ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1138326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean ccVisible = mCcBccView.isCcVisible(); 1139326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean bccVisible = mCcBccView.isBccVisible(); 1140ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1141326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (!ccVisible || !bccVisible) { 1142ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 1143326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label 1144ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1145ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1146ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 1147ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1148ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 114946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 115046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1151a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira private void showCcBcc(Bundle state) { 1152326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (state != null && state.containsKey(EXTRA_SHOW_CC)) { 1153326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showCc = state.getBoolean(EXTRA_SHOW_CC); 1154326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC); 1155326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (showCc || showBcc) { 1156326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccView.show(false, showCc, showBcc); 1157326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1158326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1159326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1160326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira 1161013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 1162013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 1163013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 1164013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 1165013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 11662421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null); 11672421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 11682421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira 11695c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Uri contentUri) { 11705c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang if (contentUri == null) { 11712421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira return; 11722421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1173013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 11745c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri)); 11755c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } catch (AttachmentFailureException e) { 11765c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang // A toast has already been shown to the user, no need to do 11775c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang // anything. 11785c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang LogUtils.e(LOG_TAG, e, "Error adding attachment"); 11795c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 11805c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 11815c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang 11825c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Attachment attachment) { 11835c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang try { 11845c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang long size = mAttachmentsView.addAttachment(mAccount, attachment); 11859932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 11869932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 11879932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 1188013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 11899932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 11909932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // A toast has already been shown to the user, no need to do 11919932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // anything. 11929932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1193013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1194013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1195013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 11963ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initRecipientsFromRefMessage(String recipientAddress, Message refMessage, 119746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action) { 11984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 11994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 12004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 12014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 120233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira initReplyRecipients(mAccount.name, refMessage, action); 12034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1205818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 12063ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initReplyRecipients(String account, Message refMessage, int action) { 12074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // This is the email address of the current user, i.e. the one composing 12084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the reply. 12094a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String accountEmail = Address.getEmailAddress(account).getAddress(); 12101469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira String fromAddress = getAddress(refMessage.from); 12113ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to); 12123ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String replytoAddress = refMessage.replyTo; 1213a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 12144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 12164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 12174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 1218a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 1219a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 12203ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 12211469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira sentToAddresses); 1222a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 1223a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 12244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 12253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 12263ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 1227154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 12284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addRecipients(accountEmail, ccAddresses, sentToAddresses); 12293ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira addRecipients(accountEmail, ccAddresses, 12303ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira Utils.splitCommaSeparatedString(refMessage.cc)); 12314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 12324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12351469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira private String getAddress(String toParse) { 12361469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira if (!TextUtils.isEmpty(toParse)) { 12371469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(toParse); 12381469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira if (tokens.length > 0) { 12391469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira return tokens[0].getAddress(); 12401469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 12411469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 12421469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira return ""; 12431469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 12441469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira 12454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 12464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 12474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 12508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 12518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 12524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1254bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 1255bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 1256bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1257bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 12584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 12594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 12604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 12614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 12624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 12648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 12658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 12668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 12674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 12684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 12718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 12728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 12738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 12748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 12758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 12768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 12778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 12788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 12798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 12824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12834a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12854a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) { 12864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira HashSet<String> hash = new HashSet<String>(); 12874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (Rfc822Token[] tokens : list) { 12884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 12894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 12904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 12934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 12964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 12974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 12984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 13004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 13014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 13034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 13054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 13064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 13074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 13084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 13094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 13124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addAddressToList(String address, RecipientEditTextView list) { 13134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 13144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 13154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 13164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 13174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 13184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 13194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 13204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 13234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 13244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected Collection<String> initToRecipients(String account, String accountEmail, 13253ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String senderAddress, String replyToAddress, String[] inToAddresses) { 13264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 13274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 13284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 13294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 13304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 13314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 13323ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira if (!TextUtils.isEmpty(replyToAddress)) { 13333ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 13344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 13351469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira // TODO (mindyp): add check for custom from as well. 13361469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira if (!TextUtils.equals(senderAddress, accountEmail)) { 13371469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira toAddresses.add(senderAddress); 13381469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } else { 13391469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira // This happens if the user replies to a message they originally 13401469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira // wrote. In this case, "reply" really means "re-send," so we target the 13411469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira // original recipients. This works as expected even if the user sent the 13421469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira // original message to themselves. 13431469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira toAddresses.addAll(Arrays.asList(inToAddresses)); 13441469b4e00ea101bc86adef274cf6b4705425b7fcMindy Pereira } 13454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 13474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 13494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static void addRecipients(String account, Set<String> recipients, String[] addresses) { 13504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String email : addresses) { 13514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Do not add this account, or any of the custom froms, to the list 13524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // of recipients. 13534a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 13544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (!account.equalsIgnoreCase(recipientAddress)) { 13554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 13564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 13574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 135846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 135946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 13603ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void setSubject(Message refMessage, int action) { 13613ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String subject = refMessage.subject; 136246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 136346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 136446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 136546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 136646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 136746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.forward_subject_label); 136846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 136946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.reply_subject_label); 137046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 137146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 137246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 137346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (subject.toLowerCase().startsWith(prefix.toLowerCase())) { 137446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 137546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 137646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = String 137746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira .format(getString(R.string.formatted_subject), prefix, subject); 137846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 137946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mSubject.setText(correctedSubject); 138046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 138146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1382818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 1383818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 1384818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 1385818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 1386eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1387eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1388818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 1389679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 1390c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira view.setTokenizer(new Rfc822Tokenizer()); 139182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 1392679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook final String accountName = mAccount.name; 139333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 139433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 1395c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira if (offset > -1) { 139633fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira account = account.substring(accountName.indexOf("@") + 1); 1397c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 139882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 1399c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 140082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 14018e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 14028e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 14038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 14048e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 14058e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira int id = v.getId(); 14068e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira switch (id) { 1407a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira case R.id.add_cc_bcc: 14088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Verify that cc/ bcc aren't showing. 14098e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Animate in cc/bcc. 1410a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira showCcBccViews(); 14118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira break; 14121f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.add_attachment: 14138f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein openAttachmentTypeSelectionDialog(); 14141f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 14158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 14168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1417b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1418b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1419b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 1420b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira super.onCreateOptionsMenu(menu); 1421b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1422b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 142382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 142482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 14253ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem helpItem = menu.findItem(R.id.help_info_menu_item); 14263ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item); 14273ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (helpItem != null) { 14283ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira helpItem.setVisible(mAccount != null 14293ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT)); 14303ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 14313ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (sendFeedbackItem != null) { 14323ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira sendFeedbackItem.setVisible(mAccount != null 14333ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK)); 14343ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 1435b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1436b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1437b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1438b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1439ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 1440ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 1441818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 1442ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1443ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 1444ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 1445ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 1446ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 1447ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 1448ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1449ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1450ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 1451ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1452ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 145375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (mSave != null) { 145475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSave.setEnabled(shouldSave()); 145575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 1456ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 1457ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1458ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1459ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 1460b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 1461b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira int id = item.getItemId(); 146275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 1463b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira switch (id) { 14647b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira case R.id.add_attachment: 14658f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein openAttachmentTypeSelectionDialog(); 14667b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira break; 1467ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira case R.id.add_cc_bcc: 1468ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira showCcBccViews(); 1469b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira break; 147033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.save: 147148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira doSave(true); 147233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 147333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.send: 147433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira doSend(); 147575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira break; 1476efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira case R.id.discard: 1477efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira doDiscard(); 1478efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira break; 14791f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.settings: 14801f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira Utils.showSettings(this, mAccount); 14811f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 1482fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case android.R.id.home: 1483daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook onAppUpPressed(); 1484fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1485fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.help_info_menu_item: 1486fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira // TODO: enable context sensitive help 1487498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook Utils.showHelp(this, mAccount, null); 1488fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1489fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.feedback_menu_item: 1490fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira Utils.sendFeedback(this, mAccount); 1491fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 149275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira default: 149375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira handled = false; 149433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 1495b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1496b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 1497b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1498326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1499daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook private void onAppUpPressed() { 1500daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook if (mLaunchedFromEmail) { 1501daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // If this was started from Gmail, simply treat app up as the system back button, so 1502daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // that the last view is restored. 1503daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook onBackPressed(); 1504daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook return; 1505daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 1506daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 1507daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Fire the main activity to ensure it launches the "top" screen of mail. 1508daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // Since the main Activity is singleTask, it should revive that task if it was already 1509daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook // started. 1510daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook final Intent mailIntent = 1511daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook Utils.createViewFolderIntent(mAccount.settings.defaultInbox, mAccount, null, false); 1512daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 1513daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook mailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | 1514daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook Intent.FLAG_ACTIVITY_TASK_ON_HOME); 1515daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook startActivity(mailIntent); 1516daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook finish(); 1517daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook } 1518daecb4b9b20a609b27fc803390ecf4f524b76089Paul Westbrook 151933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 152082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira sendOrSaveWithSanityChecks(false, true, false); 152133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 152233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 152348e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira private void doSave(boolean showToast) { 152448e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira // Clear the IME composing suggestions from the body and subject before saving. 152548e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira clearImeText(mBodyView); 152648e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira clearImeText(mSubject); 1527eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira sendOrSaveWithSanityChecks(true, showToast, false); 152848e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira } 152948e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira 153048e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira private void clearImeText(TextView v) { 153148e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira v.clearComposingText(); 153248e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira BaseInputConnection.removeComposingSpans(v.getEditableText()); 153382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 153482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1535e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1536e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public interface SendOrSaveCallback { 153782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 15387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 15397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 154082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 154182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 154282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1543e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1544e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveTask implements Runnable { 154582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 154682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 1547e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveCallback mSendOrSaveCallback; 1548e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1549e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final SendOrSaveMessage mSendOrSaveMessage; 155082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 155182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 155282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira SendOrSaveCallback callback) { 155382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 155482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 155582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 155682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 155782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 155882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 155982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 15607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 156182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 156292551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount; 15637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 15647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 156582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 156682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 156782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 15687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) { 156982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 157082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 157182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 157282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 157392551d057965689f1952faeb06763f0762bc717fMindy Pereira if (selectedAccount.account.expungeMessageUri != null) { 157492551d057965689f1952faeb06763f0762bc717fMindy Pereira resolver.update(selectedAccount.account.expungeMessageUri, values, null, 1575eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira null); 1576cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1577cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 1578eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 157982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 158082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 158182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 158282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 158382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 158482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 158582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) { 15867ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 158782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext.getContentResolver().update( 15887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri), 15897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues, null, null); 159082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } else { 15917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira ContentResolver resolver = mContext.getContentResolver(); 159292551d057965689f1952faeb06763f0762bc717fMindy Pereira Uri messageUri = resolver 159392551d057965689f1952faeb06763f0762bc717fMindy Pereira .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri 159492551d057965689f1952faeb06763f0762bc717fMindy Pereira : selectedAccount.account.sendMessageUri, 159592551d057965689f1952faeb06763f0762bc717fMindy Pereira sendOrSaveMessage.mValues); 15967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sendOrSaveMessage.mSave && messageUri != null) { 15977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Cursor messageCursor = resolver.query(messageUri, 15987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira UIProvider.MESSAGE_PROJECTION, null, null, null); 1599ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor != null) { 1600ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 1601ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor.moveToFirst()) { 1602ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // Broadcast notification that a new message has 1603ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // been allocated 1604ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 1605ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook new Message(messageCursor)); 1606ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 1607ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } finally { 1608ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook messageCursor.close(); 1609ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 16107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 16117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 161282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 161382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 16147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!sendOrSaveMessage.mSave) { 161582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 16167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 161782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 16187ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 161982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 16207ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 162182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 162282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 162382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 162482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 162582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 162682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Array of the outstanding send or save tasks. Access is synchronized 162782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // with the object itself 162882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /* package for testing */ 1629e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1630e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 163182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRequestId; 1632bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String mSignature; 16338f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein private AttachmentTypeSelectorAdapter mAttachmentTypeSelectorAdapter; 163482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1635e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1636e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static class SendOrSaveMessage { 163792551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount mAccount; 163882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 16393ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 1640e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira @VisibleForTesting 1641e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public final boolean mSave; 164282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 164382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 164492551d057965689f1952faeb06763f0762bc717fMindy Pereira public SendOrSaveMessage(ReplyFromAccount account, ContentValues values, 16453ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String refMessageId, boolean save) { 164682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 164782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 164882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 164982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 165082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 165182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 165282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 165382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 165482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 165582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 165682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 165782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 165882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 165982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 166082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 166182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 166282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 166382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 166482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 166582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 166682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 166782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 166882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 166982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 167082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 167182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 167282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 167382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 167482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 167582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 167682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 167782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 167882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 167982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 168082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 168182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 168282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 168382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 168482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 168582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 168682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 168782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 168882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 168982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 169082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 169182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 169282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 169382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 169482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 169582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 169682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 169782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) { 169882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (String email : to) { 169982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 170082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 170182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 170282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 170382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 170482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 170582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 170682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 170782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 170882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 170982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void showRecipientErrorDialog(String message) { 171082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Only 1 invalid recipients error dialog should be allowed up at a 171182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // time. 171282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mRecipientErrorDialog != null) { 171382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog.dismiss(); 171482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 171582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle( 171682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.recipient_error_dialog_title) 171782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 171882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setPositiveButton( 171982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.ok, new Dialog.OnClickListener() { 17200bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 172182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 172282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // after the user dismisses the recipient error 172382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // dialog we want to make sure to refocus the 172482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // recipient to field so they can fix the issue 172582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // easily 172682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mTo != null) { 172782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTo.requestFocus(); 172882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 172982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = null; 173082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 173182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira }).show(); 173282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 173382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 173482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 173582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 173682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 173782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 1738eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 173982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 174082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 174182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 174282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 174382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 174482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 174582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 174682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 174782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 17487ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 174982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 175082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 175182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 175282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 1753eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return (mTextChanged || mAttachmentsChanged || 175482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira (mReplyFromChanged && !isBlank())); 175582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 175682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 175782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 175882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1759bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 176082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 176182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 176282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 176382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 1764bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 1765bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 1766bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 1767bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 1768bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 1769bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1770bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1771bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 1772bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 1773bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 1774bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1775bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 1776bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 1777bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1778bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1779bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 1780bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 1781bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 1782bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 1783bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1784bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 1785bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 1786bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 1787bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 1788bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 1789bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 1790bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 1791bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 1792bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1793bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 179482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 179582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 179682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 179782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 179882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 179982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 180082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 180182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 1802eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 180382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 180433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 180533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 180682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1807181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param body 1808181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 1809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 1810181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 1811181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1812181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 1813181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira final boolean orientationChanged) { 1814181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1815181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Editable body = mBodyView.getEditableText(); 1816181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1817181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1818181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1819181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1820181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1821181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1822181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1823181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1824181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 1825181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 1826181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 1827181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 1828181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 1832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 1834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 1835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 1836181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1837181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1838181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 1839181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 1840181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 1841181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 1842181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 1843181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1844181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1845181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1846181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 18470bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 1848181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onClick(DialogInterface dialog, int which) { 1849181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged); 1850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1852181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1853181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 1854181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1855181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 1856181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 1857181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean emptyBody = TextUtils.getTrimmedLength(body) == 0; 1858181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1859181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 1860181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 1861181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 1862181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 1863181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1864181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 1865181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 1866181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 1867181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 1868181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener); 1869181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1870181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1871181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1872181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 1873181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener); 1874181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1875181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1876181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1877181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 1878181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 1879181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message, listener); 1880181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1881181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1882181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1883181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1884181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(body, save, showToast, false); 1885181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1886181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1887181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1888181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1889181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 1890181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 18915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang * 1892181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 1893181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1894181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 1895181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 1896181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1897181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1898181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1899181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 1900181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1901181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 1902181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1903181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 1904181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 1905181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1906181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1907181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) { 1908181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendConfirmDialog != null) { 1909181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog.dismiss(); 1910181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = null; 1911181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1912181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId) 1913181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setTitle(R.string.confirm_send_title) 1914181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 1915181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setPositiveButton(R.string.send, listener) 19166edd597b1a6628660284f03442cce1f193af66dcMindy Pereira .setNegativeButton(R.string.cancel, this) 19176edd597b1a6628660284f03442cce1f193af66dcMindy Pereira .show(); 1918181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1919181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1920181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1921181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 1922181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 1923181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 1924181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1925181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 1926181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 1927181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1928181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1929181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1930181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 1931181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1932181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 1933181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1934181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 1935181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 1936181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 1937181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 1938181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1939181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1940181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 1941e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount, 194205b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook Message message, final Message refMessage, Spanned body, final CharSequence quotedText, 194305b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) { 194429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira ContentValues values = new ContentValues(); 194529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 1946c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira String refMessageId = refMessage != null ? refMessage.uri.toString() : ""; 1947c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira 1948e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putToAddresses(values, message.getToAddresses()); 1949e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCcAddresses(values, message.getCcAddresses()); 1950e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putBccAddresses(values, message.getBccAddresses()); 195129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 1952e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCustomFromAddress(values, message.from); 195392551d057965689f1952faeb06763f0762bc717fMindy Pereira 1954e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putSubject(values, message.subject); 195529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira String htmlBody = Html.toHtml(body); 195605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook 195729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 195829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 195929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 1960e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 1961e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 1962e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 1963e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 196455271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook final int quoteStartPos = fullBody.length() + pos; 196555271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook fullBody.append(text); 196655271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook MessageModification.putQuoteStartPos(values, quoteStartPos); 196712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 1968e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 196929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 1970e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 1971e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 1972e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 1973e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 197429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 197529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 1976002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = getDraftType(composeMode); 197712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 1978c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (refMessage != null) { 1979c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyHtml)) { 1980c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1981c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 1982c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyText)) { 1983c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 1984c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 1985c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } else { 1986c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1987c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 1988c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira } 1989e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putAttachments(values, message.getAttachments()); 199012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 199112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 199212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 199382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 199492551d057965689f1952faeb06763f0762bc717fMindy Pereira SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount, 1995181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira values, refMessageId, save); 1996181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback); 199782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1998181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 199982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2000181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 2001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 2002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 200382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2004181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 2005181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 200682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2007002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira private static int getDraftType(int mode) { 2008002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = -1; 2009002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira switch (mode) { 2010002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.COMPOSE: 2011002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.COMPOSE; 2012002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2013002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY: 2014002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY; 2015002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2016002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY_ALL: 2017002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY_ALL; 2018002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2019002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.FORWARD: 2020002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.FORWARD; 2021002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 2022002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2023002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira return draftType; 2024002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 2025002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira 2026181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void sendOrSave(Spanned body, boolean save, boolean showToast, 2027181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean orientationChanged) { 2028181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 2029181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 20303ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook if (ActivityManager.isUserAMonkey()) { 2031181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 2032181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 203382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2034181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 2035181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 2036181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 2037181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 2038181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 2039181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 2040181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 2041181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 204282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2043181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 204482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 204582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 20460bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 204782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 2048181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 2049181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 2050181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 2051181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 2052181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 2053181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 2054181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2055181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2056181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 2057181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2058181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 2059181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 2060181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2061181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 206282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 20630bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 20647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 20657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 2066181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 2067181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 2068181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 20697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 20707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 20717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2072181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 2073181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 2074181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2075181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 20767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 2077181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2078181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 207982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 20800bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 20817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 20827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 20837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 20847ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 20857ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 208682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 20870bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 20887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 20897ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 20907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 20917ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 20927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 20937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 20947ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 20957ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 20967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 20977ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 20987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 209982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 21007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 21017ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 21027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 21037ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 21047ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 21057ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 210682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 21077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 21087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 21097ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 21107ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 21117ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 21127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 21137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 21147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 2115181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 2116181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2117181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Get the selected account if the from spinner has been setup. 211892551d057965689f1952faeb06763f0762bc717fMindy Pereira ReplyFromAccount selectedAccount = mReplyFromAccount; 2119181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String fromAddress = selectedAccount.name; 2120181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (selectedAccount == null || fromAddress == null) { 2121181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // We don't have either the selected account or from address, 2122181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // use mAccount. 212392551d057965689f1952faeb06763f0762bc717fMindy Pereira selectedAccount = mReplyFromAccount; 2124181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira fromAddress = mAccount.name; 2125181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2126181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2127181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 2128181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 2129181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 2130181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2131181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 2132181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2133181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2134e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message msg = createMessage(mReplyFromAccount, getMode()); 213505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body, 213605b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mQuotedTextView.getQuotedTextIfIncluded(), callback, 213712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira mSendSaveTaskHandler, save, mComposeMode); 2138181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2139181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mRecipient != null && mRecipient.equals(mAccount.name)) { 2140181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRecipient = selectedAccount.name; 2141181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2142b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(selectedAccount.account); 2143181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2144181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 2145181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 2146181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 2147181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 2148181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 2149181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 2150181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2151181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2152181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 2153181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 2154181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 2155181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 2156181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2157181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 2158181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2159181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 2160181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2161181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2162181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2163181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2164181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 2165181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 2166181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 2167181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2168181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 2169181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 2170181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 217182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 21728f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein public void openAttachmentTypeSelectionDialog() { 21738f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein AlertDialog.Builder builder = new AlertDialog.Builder(this); 21748f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein builder.setTitle(R.string.add_file_attachment); 21758f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein builder.setAdapter(new AttachmentTypeSelectorAdapter(this), 21768f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein new DialogInterface.OnClickListener() { 21778f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein public void onClick(DialogInterface dialog, int position) { 21788f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein doAttach(position); 21798f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein } 21808f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein }); 21818f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein builder.show(); 21828f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein } 21838f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein 21848f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein private void doAttach(int position) { 2185013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 2186013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 2187d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 21888f1c01e908d5986e8222dfd45ab82d6895b1ff3bAndrew Sapperstein i.setType(AttachmentTypeSelectorAdapter.ITEMS.get(position).mMimeType); 2189013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 2190181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 2191181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 2192013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 2193013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 2194ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 2195a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 2196ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 2197ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 2198ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2199ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2200ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 2201326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2202326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 2203a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 2204326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 2205326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 2206326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 2207326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 2208326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 2209326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 2210326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2211a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 2212154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 2213ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mDraft == null && mRefMessage != null) { 22148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromRefMessage(mComposeMode, mAccount.name); 22158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 2216ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showCc = false; 2217ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira boolean showBcc = false; 2218ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira if (mDraft != null) { 2219ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Following desktop behavior, if the user has added a BCC 2220ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // field to a draft, we show it regardless of compose mode. 2221ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira showBcc = !TextUtils.isEmpty(mDraft.bcc); 2222ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // Use the draft to determine what to populate. 2223ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira // If the Bcc field is showing, show the Cc field whether it is populated or not. 2224ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira showCc = showBcc || (!TextUtils.isEmpty(mDraft.cc) && mComposeMode == REPLY_ALL); 2225ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } else if (mRefMessage != null) { 2226ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira showCc = mComposeMode == REPLY_ALL && !TextUtils.isEmpty(mRefMessage.cc); 2227ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira } 2228ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira mCcBccView.show(false, showCc, showBcc); 2229a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 2230ef38830943dac17adb4cade670b5ae0c6b4442c6Mindy Pereira updateHideOrShowCcBcc(); 2231326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 2232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2233326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2234154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira private void resetMessageForModeChange() { 2235154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 2236154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 2237154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 2238154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 2239154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 2240154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 2241154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 2242154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 2243154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 2244154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 2245154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 2246154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 2247154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2248154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 2249154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 2250154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 2251154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 2252154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 2253154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 2254154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2255154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2256154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2257326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 2258326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2259326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 2260326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2261326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 2262326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 2263326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 2264326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2265326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2266326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 2267326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 2268326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 2269326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2270326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 2271326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2272326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2273326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2274326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 2275326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 2276326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 2277326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2278326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 2279326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 2280326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2281326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 228246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 228346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 228446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 228546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 228646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 228746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 228846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 228946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 229046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 229146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 229246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 229346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 229446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 229546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 2296eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 229746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 229846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 229946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 230046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 230146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 230246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 230346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 230446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 230546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 2306bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 230746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 230846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 230946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 231046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 2311eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 2312bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 2313bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 2314bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2315bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2316bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2317bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 2318b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira String newSignature = mCachedSettings != null ? mCachedSettings.signature : null; 2319433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira boolean hasFocus = mBodyView.hasFocus(); 2320b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.equals(newSignature, mSignature)) { 2321b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mSignature = newSignature; 2322b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.isEmpty(mSignature) 2323b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira && getSignatureStartPosition(mSignature, 2324b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.getText().toString()) < 0) { 2325b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira // Appending a signature does not count as changing text. 2326b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.removeTextChangedListener(this); 2327b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 2328b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.addTextChangedListener(this); 2329b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira } 2330433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (hasFocus) { 2331433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 2332433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 2333bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2334bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2335bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2336bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 2337bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 2338bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 2339bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 2340bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2341bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 234246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 23431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 23445a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 23455a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 234692551d057965689f1952faeb06763f0762bc717fMindy Pereira mReplyFromAccount = mFromSpinner.getCurrentAccount(); 234792551d057965689f1952faeb06763f0762bc717fMindy Pereira if (!mAccount.equals(mReplyFromAccount.account)) { 2348b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(mReplyFromAccount.account); 2349b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook 2350181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 2351181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 2352181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 2353181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 2354181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 2355181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2356181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 2357181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 235882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 23591a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 236082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 236182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 236282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 236382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 236482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 236582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 236682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 236782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSend(boolean enabled) { 236882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSend != null) { 236982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend.setEnabled(enabled); 237082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 237182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 237282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 237382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 237482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Handles button clicks from any error dialogs dealing with sending 237582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * a message. 237682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 237782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 237882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 237982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira switch (which) { 238082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_POSITIVE: { 238182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira doDiscardWithoutConfirmation(true /* show toast */ ); 238282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 238382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 238482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_NEGATIVE: { 238582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If the user cancels the send, re-enable the send button. 238682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira enableSend(true); 238782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 238882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 238982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 239082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 239182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 239282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2393efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 2394efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text) 2395efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setPositiveButton(R.string.ok, this) 2396efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setNegativeButton(R.string.cancel, null) 2397efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .create().show(); 2398efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 239982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 240082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 240182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 240282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 240382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 240482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param showToast show "Message discarded" toast if true 240582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 240682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void doDiscardWithoutConfirmation(boolean showToast) { 24077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 240882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 240982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 2410b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 2411cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira if (mAccount.expungeMessageUri != null) { 2412cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 2413cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 24140bbc858506c95005f2840fa5dff495a9216d2665Marc Blank getContentResolver().delete(mDraft.uri, null, null); 2415cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 241682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 241782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 241882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 241982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 242082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 242182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 242282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 242382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 242482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (showToast) { 242582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Display a toast to let the user know 242682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 242782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 242882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 242982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 243082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 243182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 243282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 243382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2434eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 2435eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 2436eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 2437eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 2438eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 2439eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 2440eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2441eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2442eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 244348e31b07b5ac7c83dc3a009242fa915afccddb9eMindy Pereira doSave(!mAddingAttachment /* show toast */); 2444eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2445eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2446eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2447eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 2448eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 2449eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 2450eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 2451eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 245275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 245375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 245475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 245575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 245675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 24570bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 245875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 245975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 246075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 246175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 246275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 246375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 246475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 246575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 246675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 246775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 24680bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 246975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 247075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 247175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 247275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 247375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 247475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 247575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 247675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 247775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 247875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 247975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 248075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 248175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 248275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 248375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 248475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 248575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 248675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 248775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 248875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 248975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 249075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 249175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 249275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 249375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 249475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 249575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 249675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 249775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 249875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 249975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 250075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 250175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 250275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 250375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 250475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 250575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 250675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 250775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 250875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 250975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 251075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 251175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 251275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 251375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 251475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 251575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 251675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 251775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 251875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 251975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 252075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 252175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 252275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 252375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 252475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 252575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 252675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 252775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 252875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 252975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 253075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 253175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 253275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 253375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 253475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 253575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 253675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 253775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 253875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 253975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 254075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 254175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 254275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 254375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 254475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 254575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 254675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 254775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 2548e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira 2549e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira public static void registerTestSendOrSaveCallback(SendOrSaveCallback testCallback) { 2550e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira if (sTestSendOrSaveCallback != null && testCallback != null) { 2551e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira throw new IllegalStateException("Attempting to register more than one test callback"); 2552e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 2553e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira sTestSendOrSaveCallback = testCallback; 2554e011b1d1c8e2e674dfdf1985d9d13da8cc06d803Mindy Pereira } 25558183d4519ac4b576c0af41f787267db6eff2efb1Vikram Aggarwal} 2556