ComposeActivity.java revision d2bef8b371784d95f60dd3f89aa0ac3557c945ef
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; 515c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport android.view.ViewGroup; 52eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection; 53326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 55433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText; 561f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView; 576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 58013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 597b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 60c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.ex.chips.RecipientEditTextView; 625c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huangimport com.android.mail.R; 63eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener; 649932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 655a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 6630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 6733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 6830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 703ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 7182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 7292551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount; 73181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 7430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 753ca5bad62c075184920c5e331870280fc6acca16Mindy Pereiraimport com.android.mail.providers.UIProvider.AccountCapabilities; 7612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 7792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 7830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 8046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 8182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 824a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 838e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 8462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException; 8562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 8846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 89bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 9046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 9175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 9246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 9346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 941c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 95bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 9682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 9746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 9846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 995a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira RespondInlineListener, DialogInterface.OnClickListener, TextWatcher, 100b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook AttachmentDeletedListener, OnAccountChangedListener { 1016349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 10236bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int COMPOSE = -1; 10336bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int REPLY = 0; 10436bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int REPLY_ALL = 1; 10536bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int FORWARD = 2; 10636bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira static final int EDIT_DRAFT = 3; 1076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1086349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 10936bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_ACTION = "action"; 1106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 111326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_CC = "showCc"; 112326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private static final String EXTRA_SHOW_BCC = "showBcc"; 113a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira 1148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1229a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira private static final String EXTRA_FROM_ACCOUNT_STRING = "fromAccountString"; 1239a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_TO = "to"; 1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 1308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC }; 1318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 13282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 14382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 14482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 14582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Key used to store the above map 14682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids"; 1476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 1536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1546349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 155f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook static final String EXTRA_ATTACHMENTS = "attachments"; 156f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1573ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 15836bbcaeff2a6e57189e4f4818e0ccdf6317ce836Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 159bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // If this is an action to edit an existing draft messagge, this extra will hold the 160bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 161bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 1624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 163013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final String LOG_TAG = new LogUtils().getLogTag(); 164013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 165013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 166013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 1678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 1698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Max size for attachments (5 megs). Will be overridden by account settings if found. 1718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp): read this from account settings? 1728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024; 173e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_SELECTED_REPLY_FROM_ACCOUNT = "replyFromAccount"; 174e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_REQUEST_ID = "requestId"; 175e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_START = "focusSelectionStart"; 176e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_FOCUS_SELECTION_END = null; 177e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private static final String EXTRA_MESSAGE = "extraMessage"; 1788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 17982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 18082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 18182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 18282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 183c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 184c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 185c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 1868e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 1878e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 1887b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 18933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private Account mAccount; 19092551d057965689f1952faeb06763f0762bc717fMindy Pereira private ReplyFromAccount mReplyFromAccount; 191181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 19282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 1936349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 1946349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 195326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 196326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private int mComposeMode = -1; 19746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 19846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private String mRecipient; 19946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 200433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private EditText mBodyView; 2011a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 2022eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 203eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 2045a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira private FromAddressSpinner mFromSpinner; 205013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 206eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 20782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 20882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 20982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 21082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 21182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private AlertDialog mRecipientErrorDialog; 212eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private AlertDialog mSendConfirmDialog; 2133ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private Message mRefMessage; 2147ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2157ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 2167ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 2171f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira private ImageView mAttachmentsButton; 2183ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 219326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 220326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 221326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 2223ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 223bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook launch(launcher, account, message, EDIT_DRAFT); 224326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 225326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 22933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launch(launcher, account, null, COMPOSE); 2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 2373ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY); 2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2426349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 2443ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY_ALL); 2456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2503ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 2513ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, FORWARD); 2526349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2536349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2543ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static void launch(Context launcher, Account account, Message message, int action) { 2556349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 2576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 2586349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 259bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 260bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 261bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 262bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 263bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 2646349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 2656349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2668e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 2678e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 2688e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onCreate(Bundle savedInstanceState) { 2698e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 2708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 27146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 272818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 273e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Account account; 274e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message; 27571c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira boolean showQuotedText = false; 27671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira 277e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int action; 278e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_MESSAGE)) { 279e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = savedInstanceState.getInt(EXTRA_ACTION, COMPOSE); 280e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira account = savedInstanceState.getParcelable(Utils.EXTRA_ACCOUNT); 281e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) savedInstanceState.getParcelable(EXTRA_MESSAGE); 282e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) savedInstanceState.getParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE); 283e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 284e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira account = (Account)intent.getParcelableExtra(Utils.EXTRA_ACCOUNT); 285e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 286e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // Initialize the message from the message in the intent 287e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 288e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 289e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 29092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (account == null) { 29192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this); 29292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (syncingAccounts.length > 0) { 29392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook account = syncingAccounts[0]; 29492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 29592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 29692227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 29792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 298818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 299818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 300818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 302e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (message != null && action != EDIT_DRAFT) { 303e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 304e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 305a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira showCcBcc(savedInstanceState); 30671c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = message.appendRefMessageContent; 307e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (action == EDIT_DRAFT) { 308e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromDraftMessage(message); 309326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira showCcBcc(message); 310bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 311bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 312bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 313bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 314bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 315bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 316bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 317bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 318bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 319bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 320bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 321bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 322bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 323bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 324bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 325bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 326e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 32771c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = message.appendRefMessageContent; 328e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 329e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 330e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromRefMessage(action, mAccount.name); 331326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira showCcBcc(mRefMessage); 33271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira showQuotedText = true; 333e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 3348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 3358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromExtras(intent); 336bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 337bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 338bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == COMPOSE) { 339eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mQuotedTextView.setVisibility(View.GONE); 34046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 341818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira initRecipients(); 342f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook initAttachmentsFromIntent(intent); 3431a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira initActionBar(action); 344e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initFromSpinner(savedInstanceState != null ? savedInstanceState : intent.getExtras(), 345e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira action); 34675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 347433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira setFocus(action); 348326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira updateHideOrShowCcBcc(); 34971c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira updateHideOrShowQuotedText(showQuotedText); 35071c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira } 35171c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira 35271c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira private void updateHideOrShowQuotedText(boolean showQuotedText) { 35371c9e569c06ee362840c14093cf1973ecf297059Mindy Pereira mQuotedTextView.updateCheckedState(showQuotedText); 354433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 355433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 356433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private void setFocus(int action) { 357433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (action == EDIT_DRAFT) { 358433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int type = mDraft.draftType; 359433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (type) { 360433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.COMPOSE: 361433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.FORWARD: 362433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = COMPOSE; 363433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 364433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY: 365433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY_ALL: 366433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 367433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = REPLY; 368433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 369433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 370433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 371433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (action) { 372433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case FORWARD: 373433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case COMPOSE: 374433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mTo.requestFocus(); 375433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 376433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY: 377433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY_ALL: 378433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 379433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 380433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 381433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 382433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 383433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 384433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira /** 385433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira * Focus the body of the message. 386433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira */ 387433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira public void focusBody() { 388433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.requestFocus(); 389433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int length = mBodyView.getText().length(); 390433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 391433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int signatureStartPos = getSignatureStartPosition( 392433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mSignature, mBodyView.getText().toString()); 393433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (signatureStartPos > -1) { 394433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // In case the user deleted the newlines... 395433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(signatureStartPos); 396433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } else if (length > 0) { 397433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // Move cursor to the end. 398433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(length); 399433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 4001a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 4011a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 4021a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 4031a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 4041a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 4051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 4061a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 407818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 40862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount); 409818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 4101a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 4111a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 412eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 413eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 414eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 415eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 416eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mSendConfirmDialog != null) { 417eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mSendConfirmDialog.dismiss(); 418eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 419eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mRecipientErrorDialog != null) { 420eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mRecipientErrorDialog.dismiss(); 421eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 422eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveIfNeeded(); 423eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 424eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 425eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 426eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 427eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAddingAttachment = false; 428eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 429eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) { 430eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 431eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 432eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 433eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 434eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 435e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira public final void onRestoreInstanceState(Bundle savedInstanceState) { 436e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira super.onRestoreInstanceState(savedInstanceState); 437e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState != null) { 438e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (savedInstanceState.containsKey(EXTRA_FOCUS_SELECTION_START)) { 439e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int selectionStart = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_START); 440e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int selectionEnd = savedInstanceState.getInt(EXTRA_FOCUS_SELECTION_END); 441e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // There should be a focus and it should be an EditText since we 442e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // only save these extras if these conditions are true. 443e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) getCurrentFocus(); 444e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira final int length = focusEditText.getText().length(); 445e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectionStart < length && selectionEnd < length) { 446e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira focusEditText.setSelection(selectionStart, selectionEnd); 447e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 448e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 449e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 450e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 451e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 452e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira @Override 453eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public final void onSaveInstanceState(Bundle state) { 454eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 455e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // The framework is happy to save and restore the selection but only if it also saves and 456e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // restores the contents of the edit text. That's a lot of text to put in a bundle so we do 457e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // this manually. 458e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira View focus = getCurrentFocus(); 459e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (focus != null && focus instanceof EditText) { 460e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira EditText focusEditText = (EditText) focus; 461e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_START, focusEditText.getSelectionStart()); 462e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_FOCUS_SELECTION_END, focusEditText.getSelectionEnd()); 463e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 4646273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook 4656273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 466151f1ad1613ecac0207144472872440517172b5aPaul Westbrook final int selectedPos = mFromSpinner.getSelectedItemPosition(); 4676273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook final ReplyFromAccount selectedReplyFromAccount = 468151f1ad1613ecac0207144472872440517172b5aPaul Westbrook (replyFromAccounts.size() > 0 && replyFromAccounts.size() > selectedPos) ? 469151f1ad1613ecac0207144472872440517172b5aPaul Westbrook replyFromAccounts.get(selectedPos) : 4706273e96b7204a33ea44823fb36fd7fc8baf5ba20Paul Westbrook null; 471e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (selectedReplyFromAccount != null) { 472e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT, selectedReplyFromAccount.serialize() 473e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .toString()); 474e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, selectedReplyFromAccount.account); 475e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else { 476e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(Utils.EXTRA_ACCOUNT, mAccount); 477e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 478eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 479e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraftId == UIProvider.INVALID_MESSAGE_ID && mRequestId !=0) { 480e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We don't have a draft id, and we have a request id, 481e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // save the request id. 482e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_REQUEST_ID, mRequestId); 483e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 484e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 485e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // We want to restore the current mode after a pause 486e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira // or rotation. 487e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = getMode(); 488e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putInt(EXTRA_ACTION, mode); 489e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 490e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = createMessage(selectedReplyFromAccount, mode); 491e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_MESSAGE, message); 492e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 493e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null) { 494e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira state.putParcelable(EXTRA_IN_REFERENCE_TO_MESSAGE, mRefMessage); 495e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 496326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_CC, mCcBccView.isCcVisible()); 497326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira state.putBoolean(EXTRA_SHOW_BCC, mCcBccView.isBccVisible()); 498e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 499e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 500e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private int getMode() { 501e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira int mode = ComposeActivity.COMPOSE; 502e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ActionBar actionBar = getActionBar(); 503e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (actionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_LIST) { 504e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mode = actionBar.getSelectedNavigationIndex(); 505e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 506e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return mode; 507e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 508e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 509e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private Message createMessage(ReplyFromAccount selectedReplyFromAccount, int mode) { 510e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message message = new Message(); 511e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.id = UIProvider.INVALID_MESSAGE_ID; 512e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.serverId =UIProvider.INVALID_MESSAGE_ID; 513e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.uri = null; 514e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.conversationUri = null; 515e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.subject = mSubject.getText().toString(); 516e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.snippet = null; 51791906814d08fe6bcfcd97f25f5a01d36d9d5dc73Paul Westbrook message.from = selectedReplyFromAccount != null ? 51891906814d08fe6bcfcd97f25f5a01d36d9d5dc73Paul Westbrook selectedReplyFromAccount.name : mAccount.name; 519e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.to = mTo.getText().toString(); 5204b1377e9f7677671eda0d5508a0603ec7433d19dMindy Pereira message.cc = mCc.getText().toString(); 5214b1377e9f7677671eda0d5508a0603ec7433d19dMindy Pereira message.bcc = mBcc.getText().toString(); 522e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.replyTo = null; 523e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.dateReceivedMs = 0; 524e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira String htmlBody = Html.toHtml(mBodyView.getText()); 525e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 526e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyHtml = fullBody.toString(); 527e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.bodyText = mBodyView.getText().toString(); 528e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.embedsExternalResources = false; 529e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.refMessageId = mRefMessage != null ? mRefMessage.uri.toString() : null; 530d2bef8b371784d95f60dd3f89aa0ac3557c945efMindy Pereira message.draftType = getDraftType(mode); 531e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.appendRefMessageContent = mQuotedTextView.getQuotedTextIfIncluded() != null; 532e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira ArrayList<Attachment> attachments = mAttachmentsView.getAttachments(); 533e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.hasAttachments = attachments != null && attachments.size() > 0; 534e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentListUri = null; 535e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.messageFlags = 0; 536e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.saveUri = null; 537e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.sendUri = null; 538e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.alwaysShowImages = false; 539e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.attachmentsJson = Attachment.toJSONArray(attachments); 540e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira CharSequence quotedText = mQuotedTextView.getQuotedText(); 541e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.quotedTextOffset = !TextUtils.isEmpty(quotedText) ? QuotedTextView 542e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira .getQuotedTextOffset(quotedText.toString()) : -1; 543e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira message.accountUri = null; 544e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira return message; 545eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 546eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 547818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 548818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 549bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira if (account == null) { 550bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira return; 551bb5217ee950c156d761a086bfd0d1d392d224cf4Mindy Pereira } 55223e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 55323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 554b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook mCachedSettings = mAccount.settings; 555b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook appendSignature(); 55623e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 557818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 558818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 559e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromSpinner(Bundle bundle, int action) { 5609a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira String accountString = null; 561e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (action == EDIT_DRAFT && mDraft.draftType == UIProvider.DraftType.COMPOSE) { 56262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira action = COMPOSE; 56362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 56462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.asyncInitFromSpinner(action, mAccount); 5659a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle != null) { 5669a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira if (bundle.containsKey(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)) { 5679a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = ReplyFromAccount.deserialize(mAccount, 5689a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira bundle.getString(EXTRA_SELECTED_REPLY_FROM_ACCOUNT)); 5699a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } else if (bundle.containsKey(EXTRA_FROM_ACCOUNT_STRING)) { 5709a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira accountString = bundle.getString(EXTRA_FROM_ACCOUNT_STRING); 5719a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira mReplyFromAccount = mFromSpinner.getMatchingReplyFromAccount(accountString); 5729a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira } 573e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 574e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mReplyFromAccount == null) { 575e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mDraft != null) { 576e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft); 577e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } else if (mRefMessage != null) { 578e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage); 579e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 58062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 58162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mReplyFromAccount == null) { 58262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 58362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mAccount.name, true, false); 58462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 5859a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 58662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.setCurrentAccount(mReplyFromAccount); 5879a42bb4f11c502dd5c2cf92249ac214a6c2f1a70Mindy Pereira 58862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mFromSpinner.getCount() > 1) { 589a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // If there is only 1 account, just show that account. 590a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // Otherwise, give the user the ability to choose which account to 59162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // send mail from / save drafts to. 59262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromStatic.setVisibility(View.GONE); 593a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 59462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinnerWrapper.setVisibility(View.VISIBLE); 595a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } else { 596a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStatic.setVisibility(View.VISIBLE); 597a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 598a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromSpinnerWrapper.setVisibility(View.GONE); 599a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } 60046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 60146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 60262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) { 60362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (refMessage.accountUri != null) { 60462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // This must be from combined inbox. 60562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 60662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 60762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.account.uri.equals(refMessage.accountUri)) { 60862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 60962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 61062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 61162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return null; 61262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 61362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getReplyFromAccount(account, refMessage); 61462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 61562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 61662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 61762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 61862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Given an account and which email address the message was sent to, 61962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * return who the message should be sent from. 62062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param account Account in which the message arrived. 62162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param sentTo Email address to which the message was sent. 62262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @return the address from which to reply. 62362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 62462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) { 62562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // First see if we are supposed to use the default address or 62662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // the address it was sentTo. 627326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (mCachedSettings.forceReplyFromDefault) { 62862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getDefaultReplyFromAccount(account); 62962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 63062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // If we aren't explicityly told which account to look for, look at 63162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // all the message recipients and find one that matches 63262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // a custom from or account. 63362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<String> allRecipients = new ArrayList<String>(); 63462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to))); 63562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc))); 63662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getMatchingRecipient(account, allRecipients); 63762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 63862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 63962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 64062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 64162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Compare all the recipients of an email to the current account and all 64262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * custom addresses associated with that account. Return the match if there 64362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * is one, or the default account if there isn't. 64462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 64562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) { 64662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // Tokenize the list and place in a hashmap. 64762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount matchingReplyFrom = null; 64862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira Rfc822Token[] tokens; 64962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira HashSet<String> recipientsMap = new HashSet<String>(); 65062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (String address : sentTo) { 65162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira tokens = Rfc822Tokenizer.tokenize(address); 65262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (int i = 0; i < tokens.length; i++) { 65362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira recipientsMap.add(tokens[i].getAddress()); 65462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 65562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 65662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 65762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira int matchingAddressCount = 0; 65862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> customFroms; 65962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira try { 66062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira customFroms = FromAddressSpinner.getAccountSpecificFroms(account); 66162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (customFroms != null) { 66262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount entry : customFroms) { 66362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (recipientsMap.contains(entry.address)) { 66462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = entry; 66562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingAddressCount++; 66662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 66962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } catch (JSONException e) { 67062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s", 67162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira account.name); 67262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 67362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (matchingAddressCount > 1) { 67462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = getDefaultReplyFromAccount(account); 67562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 67662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return matchingReplyFrom; 67762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 67862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 67962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getDefaultReplyFromAccount(Account account) { 68062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 68162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 68262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.isDefault) { 68362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 68462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 68562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 68662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return new ReplyFromAccount(account, account.uri, account.name, account.name, true, false); 68762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 68862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 689e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message msg) { 690e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira String sender = msg.from; 69162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount replyFromAccount = null; 69262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 69362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(account.name, sender)) { 69462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 69562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mAccount.name, true, false); 69662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 69762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount fromAccount : replyFromAccounts) { 69862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(fromAccount.name, sender)) { 69962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = fromAccount; 70062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira break; 70162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 70262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 70362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 70462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return replyFromAccount; 70562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 70662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 70746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 708a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 7098e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 7108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 7118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 7128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 7137b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 7141f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment); 7151f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira if (mAttachmentsButton != null) { 7161f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton.setOnClickListener(this); 7171f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira } 718818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 719818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 720818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 72182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 72282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 7236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 72446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 72546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 726433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView = (EditText) findViewById(R.id.body); 7271a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 7282eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 729eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 7305a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 731326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 73375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 73475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 73575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 73675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 73775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 73875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 73975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this)); 74075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this)); 74175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this)); 74275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 743818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 74475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 74575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 746326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private void initActionBar(int action) { 747326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = action; 748eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 749326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (action == ComposeActivity.COMPOSE) { 750eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 751eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 752326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 753eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 754326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 755326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 756326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 757eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 758eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 759326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira switch (action) { 760326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 761eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 762326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 763326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 764eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 765326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 766326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 767eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 768326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 769326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 7706349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 771fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 772fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 773fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 7746349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 7756349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 77646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void initFromRefMessage(int action, String recipientAddress) { 7778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 7788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 7798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 7808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 7818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initRecipientsFromRefMessage(recipientAddress, mRefMessage, action); 783e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira initQuotedTextFromRefMessage(mRefMessage, action); 7848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 7858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 7866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 787c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 788c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 789e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initFromDraftMessage(Message message) { 790bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook LogUtils.d(LOG_TAG, "Intializing draft from previous draft message"); 791bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 792bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 793bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 794bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 795bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 796bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final List<String> toAddresses = Arrays.asList(message.getToAddresses()); 797bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 798bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses); 799bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addBccAddresses(Arrays.asList(message.getBccAddresses())); 8002421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (message.hasAttachments) { 8012421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira List<Attachment> attachments = message.getAttachments(); 8022421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira for (Attachment a : attachments) { 8035c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(a); 8042421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 8052421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 806002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int quotedTextIndex = message.appendRefMessageContent && !mForward ? 807002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.quotedTextOffset : -1; 808bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 809002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence quotedText = null; 810bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 811002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence htmlText = Html.fromHtml(message.bodyHtml); 812002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 813002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira htmlText = htmlText.subSequence(0, quotedTextIndex); 814002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira quotedText = message.bodyHtml.subSequence(quotedTextIndex, 815002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.bodyHtml.length()); 816002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 817002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(htmlText); 818bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 819002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira CharSequence bodyText = quotedTextIndex > -1 ? 820002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira message.bodyText.substring(0, quotedTextIndex) : message.bodyText; 821002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1) { 822002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira quotedText = message.bodyText.substring(quotedTextIndex); 823002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 824002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira mBodyView.setText(bodyText); 825002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 826002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira if (quotedTextIndex > -1 && quotedText != null) { 8273971323f24b15b541f7460c1a4db42d78eb1873bMindy Pereira mQuotedTextView.setQuotedTextFromDraft(quotedText, mForward); 828bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 829bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 830bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 8318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 8328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 8338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 8348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 8358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 8368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 8378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 8388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 8398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 8408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 8418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromExtras(Intent intent) { 8428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 8438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 8448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 8458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 8468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 8478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 8488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 8490b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira if (!mAccount.composeIntentUri.equals(dataUri)) { 8508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 8518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 8528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 853dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(toText, ","))); 8548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 8608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 8618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 8628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 8648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 8658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 8668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 8688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 8698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 8708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 8738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 8748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 8758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 8788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 8798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 8808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 881dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(value, ","))); 8828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 883dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addCcAddresses(Arrays.asList(TextUtils.split(value, ",")), null); 8848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 885dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addBccAddresses(Arrays.asList(TextUtils.split(value, ","))); 8868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 8878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 8888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 8898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 8908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 8958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 8968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 8978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 8988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 8998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 901e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira } 902e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira 9038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 9048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 9058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: handle the case where there are spaces in the display name as well as the email 9068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // such as "Guy with spaces <guy+with+spaces@gmail.com>" as they it could be encoded 9078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // ambiguously. 9088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 9108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 9118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 9128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String replacePlus = s.replace("+", "%2B"); 9138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME); 9148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 9178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 9188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 9198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 9208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 9218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 9228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 9238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 9248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 9258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 9268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 9278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 9288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 9298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 9308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 9318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 9328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 9338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 934dbe8996d8ba382bfe1a23894abbc4711e36c9daeMindy Pereira addToAddresses(Arrays.asList(TextUtils.split(to, ","))); 9358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 9368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 9378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 9388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 9398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 9408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 9448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 9458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 9478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 9488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 9508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 9518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 9538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 9548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 9558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME)); 9568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 9578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 9588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 9598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 9638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 9648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 9658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME), 9668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 9678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 9688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 9698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 9728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 9733ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void initAttachments(Message refMessage) { 9747a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira mAttachmentsView.addAttachments(mAccount, refMessage); 975eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 976eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 977f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 97803ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook Bundle extras = intent.getExtras(); 97903ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook if (extras == null) { 98003ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook extras = Bundle.EMPTY; 98103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook } 982f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 983f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 984f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 985f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 986f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 987f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 988f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 989f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 990f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 9915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 992f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 993f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 994f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 995f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 996f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 997f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 998f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 999f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1000f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) { 1001f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 1002f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1003f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 10045c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, uri); 1005f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1006f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, so just 1007f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // exit. 1008f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1009f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1010f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1011f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1012f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1013f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND_MULTIPLE.equals(action) 1014f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook && extras.containsKey(Intent.EXTRA_STREAM)) { 1015f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); 1016f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (Parcelable uri : uris) { 1017f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 1018f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 10195c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang size = mAttachmentsView.addAttachment(mAccount, (Uri) uri); 1020f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 1021f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 1022f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 1023f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1024f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1025f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 1026f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1027f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1028f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1029f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 1030f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 1031f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 1032f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1033f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1034f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 1035f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1036f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1037e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira private void initQuotedTextFromRefMessage(Message refMessage, int action) { 1038e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira if (mRefMessage != null && (action == REPLY || action == REPLY_ALL || action == FORWARD)) { 10399932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 10409932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 104146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 104246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 104346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 1044ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1045326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean ccVisible = mCcBccView.isCcVisible(); 1046326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean bccVisible = mCcBccView.isBccVisible(); 1047ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1048326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (!ccVisible || !bccVisible) { 1049ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 1050326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccButton.setText(getString(!ccVisible ? R.string.add_cc_label 1051ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1052ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1053ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 1054ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1055ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 105646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 105746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1058a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira private void showCcBcc(Bundle state) { 1059326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (state != null && state.containsKey(EXTRA_SHOW_CC)) { 1060326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showCc = state.getBoolean(EXTRA_SHOW_CC); 1061326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showBcc = state.getBoolean(EXTRA_SHOW_BCC); 1062326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (showCc || showBcc) { 1063326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccView.show(false, showCc, showBcc); 1064326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1065326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1066326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira } 1067326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira 1068326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira private void showCcBcc(Message refMessage) { 1069326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (refMessage != null) { 1070326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showCc = !TextUtils.isEmpty(refMessage.cc); 1071326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira boolean showBcc = !TextUtils.isEmpty(refMessage.bcc); 1072326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira if (showCc || showBcc) { 1073326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira mCcBccView.show(false, showCc, showBcc); 10746faeedffd7513074372ad2a4bfede496ff938e26Mindy Pereira } 1075a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira } 1076326689d531da1d2579fa7daaf6e307e24a05f993Mindy Pereira updateHideOrShowCcBcc(); 1077a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira } 1078a34c9a054c9aef6f83abe56515c132a31d71b3c8Mindy Pereira 1079013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 1080013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 1081013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 1082013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 1083013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 10842421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null); 10852421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 10862421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira 10875c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Uri contentUri) { 10885c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang if (contentUri == null) { 10892421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira return; 10902421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 1091013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 10925c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang addAttachmentAndUpdateView(mAttachmentsView.generateLocalAttachment(contentUri)); 10935c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } catch (AttachmentFailureException e) { 10945c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang // A toast has already been shown to the user, no need to do 10955c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang // anything. 10965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang LogUtils.e(LOG_TAG, e, "Error adding attachment"); 10975c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 10985c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang } 10995c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang 11005c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang public void addAttachmentAndUpdateView(Attachment attachment) { 11015c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang try { 11025c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang long size = mAttachmentsView.addAttachment(mAccount, attachment); 11039932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 11049932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 11059932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 1106013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 11079932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 11089932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // A toast has already been shown to the user, no need to do 11099932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // anything. 11109932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 1111013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1112013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1113013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 11143ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initRecipientsFromRefMessage(String recipientAddress, Message refMessage, 111546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action) { 11164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 11174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 11184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 11194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 112033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira initReplyRecipients(mAccount.name, refMessage, action); 11214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1123818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 11243ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initReplyRecipients(String account, Message refMessage, int action) { 11254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // This is the email address of the current user, i.e. the one composing 11264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the reply. 11274a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String accountEmail = Address.getEmailAddress(account).getAddress(); 11283ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String fromAddress = refMessage.from; 11293ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to); 11303ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String replytoAddress = refMessage.replyTo; 1131a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 11324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 11334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 11344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 11354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 1136a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 1137a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 11383ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 11393ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 1140a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 1141a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 11424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 11433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 11443ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 1145154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 11464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addRecipients(accountEmail, ccAddresses, sentToAddresses); 11473ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira addRecipients(accountEmail, ccAddresses, 11483ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira Utils.splitCommaSeparatedString(refMessage.cc)); 11494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 11504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 11534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 11544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 11554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 11574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 11588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 11598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 11604a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11614a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 1162bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 1163bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 1164bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 1165bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 11664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 11674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 11684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 11694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 11704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 11718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 11728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 11738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 11748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 11754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 11764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 11798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 11808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 11818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 11828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 11838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 11848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 11858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 11868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 11878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 11904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11914a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11924a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 11934a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) { 11944a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira HashSet<String> hash = new HashSet<String>(); 11954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (Rfc822Token[] tokens : list) { 11964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 11974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 11984a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 11994a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12004a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 12014a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12024a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12034a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 12044a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 12054a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 12064a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12074a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 12084a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 12094a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 12114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 12144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 12154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 12164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 12174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addAddressToList(String address, RecipientEditTextView list) { 12214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 12224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 12234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 12254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 12274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 12284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 12324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected Collection<String> initToRecipients(String account, String accountEmail, 12333ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String senderAddress, String replyToAddress, String[] inToAddresses) { 12344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 12354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 12364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 12374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 12384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 12394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 12403ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira if (!TextUtils.isEmpty(replyToAddress)) { 12413ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 12424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 12433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(senderAddress); 12444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 12464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 12484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static void addRecipients(String account, Set<String> recipients, String[] addresses) { 12494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String email : addresses) { 12504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Do not add this account, or any of the custom froms, to the list 12514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // of recipients. 12524a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 12534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (!account.equalsIgnoreCase(recipientAddress)) { 12544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 12554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 12564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 125746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 125846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 12593ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void setSubject(Message refMessage, int action) { 12603ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String subject = refMessage.subject; 126146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 126246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 126346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 126446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 126546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 126646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.forward_subject_label); 126746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 126846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.reply_subject_label); 126946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 127046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 127146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 127246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (subject.toLowerCase().startsWith(prefix.toLowerCase())) { 127346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 127446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 127546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = String 127646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira .format(getString(R.string.formatted_subject), prefix, subject); 127746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 127846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mSubject.setText(correctedSubject); 127946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 128046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1281818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 1282818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 1283818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 1284818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 1285eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1286eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1287818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 1288679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 1289c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira view.setTokenizer(new Rfc822Tokenizer()); 129082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 1291679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook final String accountName = mAccount.name; 129233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 129333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 1294c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira if (offset > -1) { 129533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira account = account.substring(accountName.indexOf("@") + 1); 1296c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 129782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 1298c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 129982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 13008e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 13018e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 13028e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 13038e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 13048e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira int id = v.getId(); 13058e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira switch (id) { 1306a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira case R.id.add_cc_bcc: 13078e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Verify that cc/ bcc aren't showing. 13088e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Animate in cc/bcc. 1309a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira showCcBccViews(); 13108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira break; 13111f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.add_attachment: 13121f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira doAttach(); 13131f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 13148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 13158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1316b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1317b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1318b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 1319b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira super.onCreateOptionsMenu(menu); 1320b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1321b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 132282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 132382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 13243ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem helpItem = menu.findItem(R.id.help_info_menu_item); 13253ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira MenuItem sendFeedbackItem = menu.findItem(R.id.feedback_menu_item); 13263ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (helpItem != null) { 13273ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira helpItem.setVisible(mAccount != null 13283ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT)); 13293ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 13303ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira if (sendFeedbackItem != null) { 13313ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira sendFeedbackItem.setVisible(mAccount != null 13323ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira && mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK)); 13333ca5bad62c075184920c5e331870280fc6acca16Mindy Pereira } 1334b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1335b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1336b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1337b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1338ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 1339ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 1340818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 1341ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1342ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 1343ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 1344ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 1345ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 1346ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 1347ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1348ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1349ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 1350ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1351ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 135275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (mSave != null) { 135375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSave.setEnabled(shouldSave()); 135475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 1355ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 1356ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1357ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1358ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 1359b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 1360b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira int id = item.getItemId(); 136175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 1362b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira switch (id) { 13637b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira case R.id.add_attachment: 1364013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira doAttach(); 13657b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira break; 1366ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira case R.id.add_cc_bcc: 1367ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira showCcBccViews(); 1368b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira break; 136933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.save: 1370eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSave(true, false); 137133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 137233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.send: 137333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira doSend(); 137475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira break; 1375efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira case R.id.discard: 1376efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira doDiscard(); 1377efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira break; 13781f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.settings: 13791f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira Utils.showSettings(this, mAccount); 13801f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 1381fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case android.R.id.home: 1382fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira finish(); 1383fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1384fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.help_info_menu_item: 1385fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira // TODO: enable context sensitive help 1386498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook Utils.showHelp(this, mAccount, null); 1387fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1388fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.feedback_menu_item: 1389fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira Utils.sendFeedback(this, mAccount); 1390fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 139175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira default: 139275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira handled = false; 139333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 1394b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1395b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 1396b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1397326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 139833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 139982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira sendOrSaveWithSanityChecks(false, true, false); 140033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 140133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 1402eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void doSave(boolean showToast, boolean resetIME) { 1403eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira sendOrSaveWithSanityChecks(true, showToast, false); 1404eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (resetIME) { 1405eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // Clear the IME composing suggestions from the body. 1406eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira BaseInputConnection.removeComposingSpans(mBodyView.getEditableText()); 1407eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 140882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 140982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 141082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ interface SendOrSaveCallback { 141182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 14127ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 14137ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 141482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 141582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 141682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 141782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ static class SendOrSaveTask implements Runnable { 141882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 141982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final SendOrSaveCallback mSendOrSaveCallback; 142082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 142182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final SendOrSaveMessage mSendOrSaveMessage; 142282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 142382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 142482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira SendOrSaveCallback callback) { 142582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 142682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 142782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 142882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 142982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 143082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 143182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 14327ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 143382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 143492551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount; 14357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 14367ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 143782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 143882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 143982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 14407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) { 144182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 144282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 144382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 144482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 144592551d057965689f1952faeb06763f0762bc717fMindy Pereira if (selectedAccount.account.expungeMessageUri != null) { 144692551d057965689f1952faeb06763f0762bc717fMindy Pereira resolver.update(selectedAccount.account.expungeMessageUri, values, null, 1447eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira null); 1448cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1449cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 1450eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 145182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 145282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 145382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 145482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 145582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 145682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 145782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) { 14587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 145982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext.getContentResolver().update( 14607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri), 14617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues, null, null); 146282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } else { 14637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira ContentResolver resolver = mContext.getContentResolver(); 146492551d057965689f1952faeb06763f0762bc717fMindy Pereira Uri messageUri = resolver 146592551d057965689f1952faeb06763f0762bc717fMindy Pereira .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri 146692551d057965689f1952faeb06763f0762bc717fMindy Pereira : selectedAccount.account.sendMessageUri, 146792551d057965689f1952faeb06763f0762bc717fMindy Pereira sendOrSaveMessage.mValues); 14687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sendOrSaveMessage.mSave && messageUri != null) { 14697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Cursor messageCursor = resolver.query(messageUri, 14707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira UIProvider.MESSAGE_PROJECTION, null, null, null); 1471ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor != null) { 1472ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 1473ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor.moveToFirst()) { 1474ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // Broadcast notification that a new message has 1475ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // been allocated 1476ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 1477ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook new Message(messageCursor)); 1478ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 1479ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } finally { 1480ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook messageCursor.close(); 1481ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 14827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 14837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 148482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 148582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 14867ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!sendOrSaveMessage.mSave) { 148782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 14887ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 148982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 14907ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 149182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 14927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 149382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 149482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 149582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 149682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 149782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 149882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Array of the outstanding send or save tasks. Access is synchronized 149982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // with the object itself 150082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /* package for testing */ 150182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 150282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRequestId; 1503bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String mSignature; 150482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 150582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ static class SendOrSaveMessage { 150692551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount mAccount; 150782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 15083ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 150982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final boolean mSave; 151082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 151182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 151292551d057965689f1952faeb06763f0762bc717fMindy Pereira public SendOrSaveMessage(ReplyFromAccount account, ContentValues values, 15133ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String refMessageId, boolean save) { 151482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 151582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 151682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 151782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 151882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 151982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 152082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 152182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 152282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 152382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 152482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 152582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 152682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 152782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 152882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 152982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 153082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 153182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 153282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 153382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 153482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 153582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 153682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 153782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 153882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 153982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 154082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 154182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 154282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 154382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 154482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 154582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 154682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 154782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 154882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 154982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 155082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 155182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 155282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 155382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 155482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 155582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 155682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 155782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 155882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 155982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 156082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 156182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 156282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 156382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 156482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 156582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) { 156682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (String email : to) { 156782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 156882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 156982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 157082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 157182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 157282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 157382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 157482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 157582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 157682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 157782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void showRecipientErrorDialog(String message) { 157882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Only 1 invalid recipients error dialog should be allowed up at a 157982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // time. 158082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mRecipientErrorDialog != null) { 158182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog.dismiss(); 158282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 158382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle( 158482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.recipient_error_dialog_title) 158582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 158682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setCancelable(false) 158782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setPositiveButton( 158882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.ok, new Dialog.OnClickListener() { 15890bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 159082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 159182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // after the user dismisses the recipient error 159282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // dialog we want to make sure to refocus the 159382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // recipient to field so they can fix the issue 159482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // easily 159582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mTo != null) { 159682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTo.requestFocus(); 159782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 159882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = null; 159982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 160082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira }).show(); 160182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 160282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 160382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 160482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 160582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 160682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 1607eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 160882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 160982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 161082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 161182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 161282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 161382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 161482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 161582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 161682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 16177ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 161882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 161982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 162082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 162182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 1622eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return (mTextChanged || mAttachmentsChanged || 162382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira (mReplyFromChanged && !isBlank())); 162482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 162582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 162682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 162782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1628bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 162982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 163082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 163182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 163282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 1633bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 1634bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 1635bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 1636bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 1637bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 1638bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1639bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1640bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 1641bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 1642bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 1643bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1644bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 1645bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 1646bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1647bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1648bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 1649bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 1650bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 1651bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 1652bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1653bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 1654bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 1655bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 1656bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 1657bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 1658bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 1659bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 1660bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 1661bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1662bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 166382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 166482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 166582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 166682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 166782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 166882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 166982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 167082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 1671eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 167282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 167333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 167433fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 167582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1676181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param body 1677181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 1678181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 1679181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 1680181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1681181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 1682181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira final boolean orientationChanged) { 1683181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1684181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Editable body = mBodyView.getEditableText(); 1685181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1688181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1690181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1694181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 1695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 1696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 1697181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 1698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 1702181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 1704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 1705181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 1706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 1709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 1710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 1711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 1712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 1713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1714181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1715181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1716181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 17170bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 1718181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onClick(DialogInterface dialog, int which) { 1719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged); 1720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1723181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 1724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 1726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 1727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean emptyBody = TextUtils.getTrimmedLength(body) == 0; 1728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 1730181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 1731181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 1732181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 1733181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1734181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 1735181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 1736181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 1737181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 1738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener); 1739181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1740181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1741181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1742181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 1743181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener); 1744181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1745181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1746181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1747181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 1748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 1749181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message, listener); 1750181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1751181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1752181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1753181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1754181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(body, save, showToast, false); 1755181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1756181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1757181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1758181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1759181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 1760181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 17615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang * 1762181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 1763181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1764181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 1765181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 1766181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1767181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1768181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1769181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 1770181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1771181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 1772181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1773181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 1774181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 1775181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1776181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1777181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) { 1778181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendConfirmDialog != null) { 1779181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog.dismiss(); 1780181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = null; 1781181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1782181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId) 1783181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setTitle(R.string.confirm_send_title) 1784181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 1785181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setPositiveButton(R.string.send, listener) 1786181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setNegativeButton(R.string.cancel, this).setCancelable(false).show(); 1787181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1788181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1789181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1790181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 1791181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 1792181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 1793181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1794181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 1795181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 1796181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1797181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1798181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1799181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 1800181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1801181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 1802181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1803181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 1804181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 1805181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 1806181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 1807181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1808181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 1810e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira static int sendOrSaveInternal(Context context, ReplyFromAccount replyFromAccount, 181105b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook Message message, final Message refMessage, Spanned body, final CharSequence quotedText, 181205b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) { 181329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira ContentValues values = new ContentValues(); 181429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 1815c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira String refMessageId = refMessage != null ? refMessage.uri.toString() : ""; 1816c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira 1817e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putToAddresses(values, message.getToAddresses()); 1818e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCcAddresses(values, message.getCcAddresses()); 1819e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putBccAddresses(values, message.getBccAddresses()); 182029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 1821e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putCustomFromAddress(values, message.from); 182292551d057965689f1952faeb06763f0762bc717fMindy Pereira 1823e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putSubject(values, message.subject); 182429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira String htmlBody = Html.toHtml(body); 182505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook 182629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 182729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 182829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 1829e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 1830e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 1831e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 1832e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 183355271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook final int quoteStartPos = fullBody.length() + pos; 183455271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook fullBody.append(text); 183555271cf624269a5a19bb1989e5904df7adec7ef7Paul Westbrook MessageModification.putQuoteStartPos(values, quoteStartPos); 183612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 1837e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 183829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 1839e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 1840e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 1841e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 1842e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 184329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 184429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 1845002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = getDraftType(composeMode); 184612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 1847c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (refMessage != null) { 1848c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyHtml)) { 1849c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1850c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 1851c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyText)) { 1852c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 1853c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 1854c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } else { 1855c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1856c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 1857c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira } 1858e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira MessageModification.putAttachments(values, message.getAttachments()); 185912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 186012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 186112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 186282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 186392551d057965689f1952faeb06763f0762bc717fMindy Pereira SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount, 1864181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira values, refMessageId, save); 1865181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback); 186682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1867181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 186882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1869181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 1870181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 1871181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 187282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1873181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 1874181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 187582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1876002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira private static int getDraftType(int mode) { 1877002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira int draftType = -1; 1878002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira switch (mode) { 1879002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.COMPOSE: 1880002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.COMPOSE; 1881002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 1882002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY: 1883002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY; 1884002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 1885002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.REPLY_ALL: 1886002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.REPLY_ALL; 1887002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 1888002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira case ComposeActivity.FORWARD: 1889002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira draftType = DraftType.FORWARD; 1890002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira break; 1891002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1892002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira return draftType; 1893002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira } 1894002ff5244800c32f2d70c96cc1110657020ee65cMindy Pereira 1895181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void sendOrSave(Spanned body, boolean save, boolean showToast, 1896181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean orientationChanged) { 1897181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 1898181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 18993ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook if (ActivityManager.isUserAMonkey()) { 1900181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 1901181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 190282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1903181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1904181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1905181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1906181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1907181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1908181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1909181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1910181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 191182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1912181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 191382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 191482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 19150bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 191682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 1917181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 1918181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 1919181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 1920181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 1921181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 1922181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 1923181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1924181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1925181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 1926181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1927181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 1928181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 1929181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1930181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 193182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 19320bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 19337ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 19347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 1935181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 1936181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 1937181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 19387ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 19397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 19407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 1941181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 1942181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 1943181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1944181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 19457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 1946181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1947181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 194882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 19490bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 19507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 19517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 19527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 19537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 19547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 195582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 19560bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 19577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 19587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 19597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 19607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 19617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 19627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 19637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 19647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 19657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 19667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 19677ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 196882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 19697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 19707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 19717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 19727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 19737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 19747ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 197582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 19767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 19777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 19787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 19797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 19807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 19817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 19827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 19837ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 1984181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1985181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1986181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Get the selected account if the from spinner has been setup. 198792551d057965689f1952faeb06763f0762bc717fMindy Pereira ReplyFromAccount selectedAccount = mReplyFromAccount; 1988181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String fromAddress = selectedAccount.name; 1989181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (selectedAccount == null || fromAddress == null) { 1990181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // We don't have either the selected account or from address, 1991181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // use mAccount. 199292551d057965689f1952faeb06763f0762bc717fMindy Pereira selectedAccount = mReplyFromAccount; 1993181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira fromAddress = mAccount.name; 1994181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1995181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1996181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 1997181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 1998181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 1999181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2000181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 2001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2003e8f94dc92567d8efa691860c38720d3ae753f429Mindy Pereira Message msg = createMessage(mReplyFromAccount, getMode()); 200405b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mRequestId = sendOrSaveInternal(this, mReplyFromAccount, msg, mRefMessage, body, 200505b92b8ff275f85edae525623c71b65805ca3a51Paul Westbrook mQuotedTextView.getQuotedTextIfIncluded(), callback, 200612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira mSendSaveTaskHandler, save, mComposeMode); 2007181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2008181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mRecipient != null && mRecipient.equals(mAccount.name)) { 2009181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRecipient = selectedAccount.name; 2010181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2011b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(selectedAccount.account); 2012181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2013181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 2014181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 2015181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 2016181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 2017181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 2018181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 2019181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2020181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2021181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 2022181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 2023181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 2024181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 2025181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2026181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 2027181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 2028181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 2029181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2030181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2031181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 2032181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 2033181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 2034181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 2035181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 2036181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 2037181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 2038181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 2039181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 204082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2041013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void doAttach() { 2042013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 2043013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 2044d6a9a3f94c69d05f23349a09d71cd36c6fb03613Paul Westbrook i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 2045181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (android.provider.Settings.System.getInt(getContentResolver(), 2046181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira UIProvider.getAttachmentTypeSetting(), 0) != 0) { 2047013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.setType("*/*"); 2048013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } else { 2049013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.setType("image/*"); 2050013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 2051013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 2052181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 2053181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 2054013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 2055013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 2056ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 2057a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 2058ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 2059ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 2060ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2061ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 2062ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 2063326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2064326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 2065a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 2066326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 2067326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 2068326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 2069326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 2070326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 2071326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 2072326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2073a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 2074154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 20758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (mRefMessage != null) { 20768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromRefMessage(mComposeMode, mAccount.name); 20778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 2078a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 2079326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 2080326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2081326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2082154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira private void resetMessageForModeChange() { 2083154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 2084154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 2085154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 2086154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 2087154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 2088154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 2089154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 2090154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 2091154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 2092154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 2093154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 2094154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 2095154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2096154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 2097154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 2098154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 2099154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 2100154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 2101154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 2102154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2103154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 2104154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 2105326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 2106326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2107326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 2108326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2109326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 2110326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 2111326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 2112326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2113326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2114326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 2115326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 2116326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 2117326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2118326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 2119326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2120326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2121326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 2122326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 2123326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 2124326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 2125326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2126326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 2127326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 2128326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 2129326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 213046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 213146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 213246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 213346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 213446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 213546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 213646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 213746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 213846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 213946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 214046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 214146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 214246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 214346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 2144eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 214546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 214646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 214746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 214846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 214946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 215046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 215146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 215246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 215346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 2154bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 215546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 215646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 215746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 215846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 2159eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 2160bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 2161bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 2162bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2163bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2164bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2165bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 2166b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira String newSignature = mCachedSettings != null ? mCachedSettings.signature : null; 2167433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira boolean hasFocus = mBodyView.hasFocus(); 2168b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.equals(newSignature, mSignature)) { 2169b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mSignature = newSignature; 2170b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.isEmpty(mSignature) 2171b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira && getSignatureStartPosition(mSignature, 2172b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.getText().toString()) < 0) { 2173b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira // Appending a signature does not count as changing text. 2174b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.removeTextChangedListener(this); 2175b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 2176b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.addTextChangedListener(this); 2177b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira } 2178433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (hasFocus) { 2179433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 2180433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 2181bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2182bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2183bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 2184bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 2185bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 2186bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 2187bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 2188bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 2189bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 219046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 21911a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 21925a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 21935a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 219492551d057965689f1952faeb06763f0762bc717fMindy Pereira mReplyFromAccount = mFromSpinner.getCurrentAccount(); 219592551d057965689f1952faeb06763f0762bc717fMindy Pereira if (!mAccount.equals(mReplyFromAccount.account)) { 2196b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(mReplyFromAccount.account); 2197b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook 2198181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 2199181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 2200181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 2201181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 2202181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 2203181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2204181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 2205181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 220682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 22071a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 220882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 220982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 221082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 221182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 221282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 221382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 221482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 221582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSend(boolean enabled) { 221682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSend != null) { 221782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend.setEnabled(enabled); 221882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 221982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 222082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 222182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 222282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Handles button clicks from any error dialogs dealing with sending 222382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * a message. 222482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 222582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 222682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 222782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira switch (which) { 222882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_POSITIVE: { 222982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira doDiscardWithoutConfirmation(true /* show toast */ ); 223082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 223182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_NEGATIVE: { 223382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If the user cancels the send, re-enable the send button. 223482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira enableSend(true); 223582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 223682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 223882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 223982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 224082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2241efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 2242efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text) 2243efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setPositiveButton(R.string.ok, this) 2244efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setNegativeButton(R.string.cancel, null) 2245efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .create().show(); 2246efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 224782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 224882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 224982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 225082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 225182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 225282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param showToast show "Message discarded" toast if true 225382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 225482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void doDiscardWithoutConfirmation(boolean showToast) { 22557ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 225682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 225782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 2258b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 2259cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira if (mAccount.expungeMessageUri != null) { 2260cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 2261cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 22620bbc858506c95005f2840fa5dff495a9216d2665Marc Blank getContentResolver().delete(mDraft.uri, null, null); 2263cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 226482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 226582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 226682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 226782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 226882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 226982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 227082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 227182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 227282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (showToast) { 227382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Display a toast to let the user know 227482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 227582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 227682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 227782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 227882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 227982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 228082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 228182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2282eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 2283eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 2284eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 2285eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 2286eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 2287eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 2288eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2289eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2290eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 2291eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSave(!mAddingAttachment /* show toast */, true /* reset IME */); 2292eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2293eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2294eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2295eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 2296eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 2297eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 2298eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 2299eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 230075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 230175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 230275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 230375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 230475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 23050bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 230675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 230775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 230875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 230975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 231075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 231175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 231275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 231375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 231475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 231575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 23160bbc858506c95005f2840fa5dff495a9216d2665Marc Blank @Override 231775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 231875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 231975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 232075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 232175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 232275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 232375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 232475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 232575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 232675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 232775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 232875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 232975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 233075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 233175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 233275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 233375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 233475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 233575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 233675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 233775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 233875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 233975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 234075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 234175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 234275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 234375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 234475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 234575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 234675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 234775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 234875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 234975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 235075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 235175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 235275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 235375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 235475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 235575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 235675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 235775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 235875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 235975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 236075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 236175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 236275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 236375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 236475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 236575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 236675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 236775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 236875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 236975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 237075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 237175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 237275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 237375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 237475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 237575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 237675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 237775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 237875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 237975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 238075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 238175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 238275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 238375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 238475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 238575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 238675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 238775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 238875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 238975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 239075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 239175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 239275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 239375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 239475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 239575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 23968183d4519ac4b576c0af41f787267db6eff2efb1Vikram Aggarwal} 2397