ComposeActivity.java revision 498e76d7efccc92386fe57c65a2ef8d5a0172604
18e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira/** 28e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Copyright (c) 2011, Google Inc. 38e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 48e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 58e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * you may not use this file except in compliance with the License. 68e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * You may obtain a copy of the License at 78e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 88e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 98e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * 108e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * Unless required by applicable law or agreed to in writing, software 118e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 128e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * See the License for the specific language governing permissions and 148e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira * limitations under the License. 158e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira */ 168e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.compose; 188e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar; 2082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.ActivityManager; 2182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.AlertDialog; 2282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.app.Dialog; 23326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.app.ActionBar.OnNavigationListener; 248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.app.Activity; 25181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.app.LoaderManager.LoaderCallbacks; 266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.ContentResolver; 2782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.ContentValues; 286349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Context; 29181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.CursorLoader; 3082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.DialogInterface; 316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.content.Intent; 32181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport android.content.Loader; 3382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.content.pm.ActivityInfo; 347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereiraimport android.database.Cursor; 356349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.net.Uri; 368e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.os.Bundle; 3782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.Handler; 3882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.os.HandlerThread; 39f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrookimport android.os.Parcelable; 4082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.provider.BaseColumns; 4146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.Editable; 4282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Html; 4382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.Spanned; 44c182762df95fd382faf8e4a25e5cf7783ea10176Paul Westbrookimport android.text.TextUtils; 4582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport android.text.TextWatcher; 4646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport android.text.util.Rfc822Token; 47c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 48326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater; 49b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.Menu; 50b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuInflater; 51b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereiraimport android.view.MenuItem; 528e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View; 53326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.ViewGroup; 548e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.view.View.OnClickListener; 55eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport android.view.inputmethod.BaseInputConnection; 56326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ArrayAdapter; 578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereiraimport android.widget.Button; 58433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereiraimport android.widget.EditText; 591f93668e1186d48b507207841c1ca0529c3de292Mindy Pereiraimport android.widget.ImageView; 606349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereiraimport android.widget.TextView; 61013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereiraimport android.widget.Toast; 627b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira 63c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.common.Rfc822Validator; 64eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentDeletedListener; 659932dee248718d2cec993d93b5115973d1389d0aMindy Pereiraimport com.android.mail.compose.AttachmentsView.AttachmentFailureException; 665a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereiraimport com.android.mail.compose.FromAddressSpinner.OnAccountChangedListener; 6730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.QuotedTextView.RespondInlineListener; 6833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account; 6930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address; 7030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Attachment; 713ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message; 7282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.android.mail.providers.MessageModification; 7392551d057965689f1952faeb06763f0762bc717fMindy Pereiraimport com.android.mail.providers.ReplyFromAccount; 74181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereiraimport com.android.mail.providers.Settings; 7530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider; 7612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereiraimport com.android.mail.providers.UIProvider.DraftType; 7730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.R; 7892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrookimport com.android.mail.utils.AccountUtils; 7930e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils; 8030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils; 81c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereiraimport com.android.ex.chips.RecipientEditTextView; 8246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport com.google.common.annotations.VisibleForTesting; 8382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport com.google.common.collect.Lists; 844a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereiraimport com.google.common.collect.Sets; 858e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 8662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereiraimport org.json.JSONException; 8762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.io.UnsupportedEncodingException; 898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereiraimport java.net.URLDecoder; 9046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.ArrayList; 91bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Arrays; 9246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.Collection; 9375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereiraimport java.util.HashMap; 9446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.HashSet; 9546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereiraimport java.util.List; 961c078cff1958b29e280100bfa6221103ec46b555Paul Westbrookimport java.util.Map.Entry; 97bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrookimport java.util.Set; 9882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereiraimport java.util.concurrent.ConcurrentHashMap; 9946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 10046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereirapublic class ComposeActivity extends Activity implements OnClickListener, OnNavigationListener, 1015a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira RespondInlineListener, DialogInterface.OnClickListener, TextWatcher, 102b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook AttachmentDeletedListener, OnAccountChangedListener { 1036349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Identifiers for which type of composition this is 104bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook static final int COMPOSE = -1; 1056349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira static final int REPLY = 0; 1066349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira static final int REPLY_ALL = 1; 1076349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira static final int FORWARD = 2; 108bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook static final int EDIT_DRAFT = 3; 1096349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1106349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira // Integer extra holding one of the above compose action 1116349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private static final String EXTRA_ACTION = "action"; 1126349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 1138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String UTF8_ENCODING_NAME = "UTF-8"; 1148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String MAIL_TO = "mailto"; 1168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_SUBJECT = "subject"; 1188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BODY = "body"; 1208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extra that we can get passed from other activities 1228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_TO = "to"; 1238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_CC = "cc"; 1248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String EXTRA_BCC = "bcc"; 1258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // List of all the fields 1278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira static final String[] ALL_EXTRAS = { EXTRA_SUBJECT, EXTRA_BODY, EXTRA_TO, EXTRA_CC, EXTRA_BCC }; 1288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 12982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static SendOrSaveCallback sTestSendOrSaveCallback = null; 13082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Map containing information about requests to create new messages, and the id of the 13182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // messages that were the result of those requests. 13282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 13382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This map is used when the activity that initiated the save a of a new message, is killed 13482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // before the save has completed (and when we know the id of the newly created message). When 13582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // a save is completed, the service that is running in the background, will update the map 13682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // 13782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // When a new ComposeActivity instance is created, it will attempt to use the information in 13882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // the previously instantiated map. If ComposeActivity.onCreate() is called, with a bundle 13982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // (restoring data from a previous instance), and the map hasn't been created, we will attempt 14082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // to populate the map with data stored in shared preferences. 14182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static ConcurrentHashMap<Integer, Long> sRequestMessageIdMap = null; 14282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Key used to store the above map 14382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private static final String CACHED_MESSAGE_REQUEST_IDS_KEY = "cache-message-request-ids"; 1446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 1456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Notifies the {@code Activity} that the caller is an Email 1466349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * {@code Activity}, so that the back behavior may be modified accordingly. 1476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * 1486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * @see #onAppUpPressed 1496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 1506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private static final String EXTRA_FROM_EMAIL_TASK = "fromemail"; 1516349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 152f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook static final String EXTRA_ATTACHMENTS = "attachments"; 153f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 1543ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira // If this is a reply/forward then this extra will hold the original message 1553ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static final String EXTRA_IN_REFERENCE_TO_MESSAGE = "in-reference-to-message"; 156bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // If this is an action to edit an existing draft messagge, this extra will hold the 157bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // draft message 158bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private static final String ORIGINAL_DRAFT_MESSAGE = "original-draft-message"; 1594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static final String END_TOKEN = ", "; 160013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final String LOG_TAG = new LogUtils().getLogTag(); 161013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira // Request numbers for activities we start 162013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_PICK_ATTACHMENT = 1; 163013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private static final int RESULT_CREATE_ACCOUNT = 2; 1648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp) set mime-type for auto send? 1658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final String AUTO_SEND_ACTION = "com.android.mail.action.AUTO_SEND"; 1668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 1678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Max size for attachments (5 megs). Will be overridden by account settings if found. 1688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO(mindyp): read this from account settings? 1698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024; 1708e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 17182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 17282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * A single thread for running tasks in the background. 17382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 17482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Handler mSendSaveTaskHandler = null; 175c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mTo; 176c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mCc; 177c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira private RecipientEditTextView mBcc; 1788e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private Button mCcBccButton; 1798e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira private CcBccView mCcBccView; 1807b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira private AttachmentsView mAttachmentsView; 18133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private Account mAccount; 18292551d057965689f1952faeb06763f0762bc717fMindy Pereira private ReplyFromAccount mReplyFromAccount; 183181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private Settings mCachedSettings; 18482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private Rfc822Validator mValidator; 1856349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira private TextView mSubject; 1866349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 187326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private ComposeModeAdapter mComposeModeAdapter; 188326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private int mComposeMode = -1; 18946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private boolean mForward; 19046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private String mRecipient; 19146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private QuotedTextView mQuotedTextView; 192433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private EditText mBodyView; 1931a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira private View mFromStatic; 1942eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira private TextView mFromStaticText; 195eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private View mFromSpinnerWrapper; 1965a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira private FromAddressSpinner mFromSpinner; 197013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira private boolean mAddingAttachment; 198eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private boolean mAttachmentsChanged; 19982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mTextChanged; 20082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean mReplyFromChanged; 20182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSave; 20282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private MenuItem mSend; 20382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private AlertDialog mRecipientErrorDialog; 204eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private AlertDialog mSendConfirmDialog; 2053ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private Message mRefMessage; 2067ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private long mDraftId = UIProvider.INVALID_MESSAGE_ID; 2077ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Message mDraft; 2087ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira private Object mDraftLock = new Object(); 2091f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira private ImageView mAttachmentsButton; 2103ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira 211326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira /** 212326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Can be called from a non-UI thread. 213326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 2143ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void editDraft(Context launcher, Account account, Message message) { 215bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook launch(launcher, account, message, EDIT_DRAFT); 216326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 217326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 2186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2196349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2206349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 22133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira public static void compose(Context launcher, Account account) { 2226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launch(launcher, account, null, COMPOSE); 2236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2246349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2256349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2266349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2276349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2283ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void reply(Context launcher, Account account, Message message) { 2293ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY); 2306349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2316349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2326349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2336349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2353ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void replyAll(Context launcher, Account account, Message message) { 2363ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, REPLY_ALL); 2376349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2386349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2396349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira /** 2406349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira * Can be called from a non-UI thread. 2416349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira */ 2423ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira public static void forward(Context launcher, Account account, Message message) { 2433ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira launch(launcher, account, message, FORWARD); 2446349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2456349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 2463ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private static void launch(Context launcher, Account account, Message message, int action) { 2476349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira Intent intent = new Intent(launcher, ComposeActivity.class); 2486349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_FROM_EMAIL_TASK, true); 2496349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(EXTRA_ACTION, action); 2506349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira intent.putExtra(Utils.EXTRA_ACCOUNT, account); 251bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == EDIT_DRAFT) { 252bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(ORIGINAL_DRAFT_MESSAGE, message); 253bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 254bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook intent.putExtra(EXTRA_IN_REFERENCE_TO_MESSAGE, message); 255bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 2566349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira launcher.startActivity(intent); 2576349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 2588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 2598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 2608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onCreate(Bundle savedInstanceState) { 2618e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira super.onCreate(savedInstanceState); 2628e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira setContentView(R.layout.compose); 26346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira findViews(); 264818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira Intent intent = getIntent(); 26592227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 26692227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook Account account = (Account)intent.getParcelableExtra(Utils.EXTRA_ACCOUNT); 26792227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (account == null) { 26892227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook final Account[] syncingAccounts = AccountUtils.getSyncingAccounts(this); 26992227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook if (syncingAccounts.length > 0) { 27092227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook account = syncingAccounts[0]; 27192227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 27292227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook } 27392227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook 27492227f6b35b3bec54609dc0feb9dd6756c2a43e6Paul Westbrook setAccount(account); 275818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mAccount == null) { 276818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira return; 277818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 27846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action = intent.getIntExtra(EXTRA_ACTION, COMPOSE); 2793ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira mRefMessage = (Message) intent.getParcelableExtra(EXTRA_IN_REFERENCE_TO_MESSAGE); 28029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if ((action == REPLY || action == REPLY_ALL || action == FORWARD)) { 2818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (mRefMessage != null) { 2828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromRefMessage(action, mAccount.name); 2838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 284bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else if (action == EDIT_DRAFT) { 285bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Initialize the message from the message in the intent 286bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final Message message = (Message) intent.getParcelableExtra(ORIGINAL_DRAFT_MESSAGE); 287bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 288bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook initFromMessage(message); 289bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 290bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Update the action to the draft type of the previous draft 291bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook switch (message.draftType) { 292bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY: 293bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY; 294bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 295bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.REPLY_ALL: 296bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = REPLY_ALL; 297bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 298bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.FORWARD: 299bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = FORWARD; 300bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 301bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook case UIProvider.DraftType.COMPOSE: 302bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook default: 303bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook action = COMPOSE; 304bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook break; 305bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 3068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 3078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromExtras(intent); 308bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 309bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 310bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (action == COMPOSE) { 311eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mQuotedTextView.setVisibility(View.GONE); 31246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 313818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira initRecipients(); 314f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook initAttachmentsFromIntent(intent); 3151a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira initActionBar(action); 316a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira initFromSpinner(action); 31775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira initChangeListeners(); 318433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira setFocus(action); 319433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 320433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 321433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira private void setFocus(int action) { 322433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (action == EDIT_DRAFT) { 323433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int type = mDraft.draftType; 324433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (type) { 325433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.COMPOSE: 326433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.FORWARD: 327433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = COMPOSE; 328433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 329433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY: 330433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case UIProvider.DraftType.REPLY_ALL: 331433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 332433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira action = REPLY; 333433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 334433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 335433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 336433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira switch (action) { 337433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case FORWARD: 338433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case COMPOSE: 339433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mTo.requestFocus(); 340433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 341433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY: 342433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira case REPLY_ALL: 343433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira default: 344433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 345433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira break; 346433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 347433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 348433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 349433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira /** 350433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira * Focus the body of the message. 351433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira */ 352433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira public void focusBody() { 353433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.requestFocus(); 354433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int length = mBodyView.getText().length(); 355433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira 356433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira int signatureStartPos = getSignatureStartPosition( 357433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mSignature, mBodyView.getText().toString()); 358433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (signatureStartPos > -1) { 359433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // In case the user deleted the newlines... 360433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(signatureStartPos); 361433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } else if (length > 0) { 362433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira // Move cursor to the end. 363433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView.setSelection(length); 364433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 3651a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 3661a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 3671a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira @Override 3681a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira protected void onResume() { 3691a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira super.onResume(); 3701a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // Update the from spinner as other accounts 3711a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira // may now be available. 372818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (mFromSpinner != null && mAccount != null) { 37362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.asyncInitFromSpinner(mComposeMode, mAccount); 374818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 3751a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 3761a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 377eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 378eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected void onPause() { 379eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onPause(); 380eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 381eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mSendConfirmDialog != null) { 382eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mSendConfirmDialog.dismiss(); 383eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 384eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mRecipientErrorDialog != null) { 385eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mRecipientErrorDialog.dismiss(); 386eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 387eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 388eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveIfNeeded(); 389eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 390eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 391eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 392eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected final void onActivityResult(int request, int result, Intent data) { 393eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAddingAttachment = false; 394eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 395eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (result == RESULT_OK && request == RESULT_PICK_ATTACHMENT) { 396eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira addAttachmentAndUpdateView(data); 397eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 398eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 399eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 400eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 401eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public final void onSaveInstanceState(Bundle state) { 402eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira super.onSaveInstanceState(state); 403eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 404eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // onSaveInstanceState is only called if the user might come back to this activity so it is 405eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // not an ideal location to save the draft. However, if we have never saved the draft before 406eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // we have to save it here in order to have an id to save in the bundle. 407eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveIfNeededOnOrientationChanged(); 408eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 409eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 410818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 411818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira void setAccount(Account account) { 41223e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira assert(account != null); 41323e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira if (!account.equals(mAccount)) { 41423e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira mAccount = account; 415b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook mCachedSettings = mAccount.settings; 416b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook appendSignature(); 41723e9fdec6872f9b4d0fbe675745cb25becf7878cMindy Pereira } 418818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira } 419818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira 420a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira private void initFromSpinner(int action) { 42162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (action == EDIT_DRAFT && 42262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mDraft.draftType == UIProvider.DraftType.COMPOSE) { 42362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira action = COMPOSE; 42462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 42562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.asyncInitFromSpinner(action, mAccount); 42662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mDraft != null) { 42762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mReplyFromAccount = getReplyFromAccountFromDraft(mAccount, mDraft); 42862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else if (mRefMessage != null) { 42962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mReplyFromAccount = getReplyFromAccountForReply(mAccount, mRefMessage); 43062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 43162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mReplyFromAccount == null) { 43262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mReplyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 43362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mAccount.name, true, false); 43462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 43562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinner.setCurrentAccount(mReplyFromAccount); 43662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (mFromSpinner.getCount() > 1) { 437a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // If there is only 1 account, just show that account. 438a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira // Otherwise, give the user the ability to choose which account to 43962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // send mail from / save drafts to. 44062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromStatic.setVisibility(View.GONE); 441a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 44262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mFromSpinnerWrapper.setVisibility(View.VISIBLE); 443a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } else { 444a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStatic.setVisibility(View.VISIBLE); 445a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromStaticText.setText(mAccount.name); 446a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira mFromSpinnerWrapper.setVisibility(View.GONE); 447a83e708e162ad1f4b04b41738882bf318e217f64Mindy Pereira } 44846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 44946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 45062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountForReply(Account account, Message refMessage) { 45162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (refMessage.accountUri != null) { 45262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // This must be from combined inbox. 45362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 45462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 45562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.account.uri.equals(refMessage.accountUri)) { 45662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 45762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 45862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 45962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return null; 46062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 46162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getReplyFromAccount(account, refMessage); 46262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 46362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 46462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 46562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 46662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Given an account and which email address the message was sent to, 46762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * return who the message should be sent from. 46862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param account Account in which the message arrived. 46962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @param sentTo Email address to which the message was sent. 47062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * @return the address from which to reply. 47162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 47262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira public ReplyFromAccount getReplyFromAccount(Account account, Message refMessage) { 47362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // First see if we are supposed to use the default address or 47462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // the address it was sentTo. 47562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (false) { //mCachedSettings.forceReplyFromDefault) { 47662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getDefaultReplyFromAccount(account); 47762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 47862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // If we aren't explicityly told which account to look for, look at 47962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // all the message recipients and find one that matches 48062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // a custom from or account. 48162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<String> allRecipients = new ArrayList<String>(); 48262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.to))); 48362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira allRecipients.addAll(Arrays.asList(Utils.splitCommaSeparatedString(refMessage.cc))); 48462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return getMatchingRecipient(account, allRecipients); 48562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 48662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 48762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 48862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira /** 48962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * Compare all the recipients of an email to the current account and all 49062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * custom addresses associated with that account. Return the match if there 49162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira * is one, or the default account if there isn't. 49262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira */ 49362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira protected ReplyFromAccount getMatchingRecipient(Account account, List<String> sentTo) { 49462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira // Tokenize the list and place in a hashmap. 49562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount matchingReplyFrom = null; 49662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira Rfc822Token[] tokens; 49762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira HashSet<String> recipientsMap = new HashSet<String>(); 49862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (String address : sentTo) { 49962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira tokens = Rfc822Tokenizer.tokenize(address); 50062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (int i = 0; i < tokens.length; i++) { 50162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira recipientsMap.add(tokens[i].getAddress()); 50262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 50362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 50462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 50562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira int matchingAddressCount = 0; 50662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> customFroms; 50762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira try { 50862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira customFroms = FromAddressSpinner.getAccountSpecificFroms(account); 50962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (customFroms != null) { 51062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount entry : customFroms) { 51162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (recipientsMap.contains(entry.address)) { 51262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = entry; 51362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingAddressCount++; 51462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 51562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 51662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 51762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } catch (JSONException e) { 51862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira LogUtils.wtf(LOG_TAG, "Exception parsing from addresses for account %s", 51962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira account.name); 52062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 52162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (matchingAddressCount > 1) { 52262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira matchingReplyFrom = getDefaultReplyFromAccount(account); 52362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 52462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return matchingReplyFrom; 52562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 52662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 52762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getDefaultReplyFromAccount(Account account) { 52862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 52962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount from : replyFromAccounts) { 53062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (from.isDefault) { 53162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return from; 53262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 53362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 53462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return new ReplyFromAccount(account, account.uri, account.name, account.name, true, false); 53562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 53662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 53762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira private ReplyFromAccount getReplyFromAccountFromDraft(Account account, Message draft) { 53862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira String sender = draft.from; 53962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira ReplyFromAccount replyFromAccount = null; 54062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira List<ReplyFromAccount> replyFromAccounts = mFromSpinner.getReplyFromAccounts(); 54162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(account.name, sender)) { 54262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = new ReplyFromAccount(mAccount, mAccount.uri, mAccount.name, 54362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira mAccount.name, true, false); 54462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } else { 54562de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira for (ReplyFromAccount fromAccount : replyFromAccounts) { 54662de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira if (TextUtils.equals(fromAccount.name, sender)) { 54762de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira replyFromAccount = fromAccount; 54862de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira break; 54962de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 55062de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 55162de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 55262de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira return replyFromAccount; 55362de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira } 55462de1b104635b09e7f00b0941268ba1fa5460ddbMindy Pereira 55546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void findViews() { 556a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccButton = (Button) findViewById(R.id.add_cc_bcc); 5578e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira if (mCcBccButton != null) { 5588e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccButton.setOnClickListener(this); 5598e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 5608e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper); 5617b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments); 5621f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton = (ImageView) findViewById(R.id.add_attachment); 5631f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira if (mAttachmentsButton != null) { 5641f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira mAttachmentsButton.setOnClickListener(this); 5651f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira } 566818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mTo = (RecipientEditTextView) findViewById(R.id.to); 567818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mCc = (RecipientEditTextView) findViewById(R.id.cc); 568818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mBcc = (RecipientEditTextView) findViewById(R.id.bcc); 56982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // TODO: add special chips text change watchers before adding 57082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // this as a text changed watcher to the to, cc, bcc fields. 5716349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira mSubject = (TextView) findViewById(R.id.subject); 57246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView = (QuotedTextView) findViewById(R.id.quoted_text_view); 57346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mQuotedTextView.setRespondInlineListener(this); 574433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira mBodyView = (EditText) findViewById(R.id.body); 5751a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira mFromStatic = findViewById(R.id.static_from_content); 5762eb173211741adf7454bbf1990ba1b9d1e1f6a64Mindy Pereira mFromStaticText = (TextView) findViewById(R.id.from_account_name); 577eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mFromSpinnerWrapper = findViewById(R.id.spinner_from_content); 5785a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira mFromSpinner = (FromAddressSpinner) findViewById(R.id.from_picker); 579326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 580326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 58175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Now that the message has been initialized from any existing draft or 58275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // ref message data, set up listeners for any changes that occur to the 58375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // message. 58475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private void initChangeListeners() { 58575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSubject.addTextChangedListener(this); 58675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBodyView.addTextChangedListener(this); 58775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTo.addTextChangedListener(new RecipientTextWatcher(mTo, this)); 58875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mCc.addTextChangedListener(new RecipientTextWatcher(mCc, this)); 58975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mBcc.addTextChangedListener(new RecipientTextWatcher(mBcc, this)); 59075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mFromSpinner.setOnAccountChangedListener(this); 591818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira mAttachmentsView.setAttachmentChangesListener(this); 59275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 59375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 594326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private void initActionBar(int action) { 595326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = action; 596eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira ActionBar actionBar = getActionBar(); 597326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (action == ComposeActivity.COMPOSE) { 598eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 599eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(R.string.compose); 600326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else { 601eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setTitle(null); 602326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mComposeModeAdapter == null) { 603326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeModeAdapter = new ComposeModeAdapter(this); 604326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 605eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 606eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setListNavigationCallbacks(mComposeModeAdapter, this); 607326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira switch (action) { 608326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY: 609eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(0); 610326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 611326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.REPLY_ALL: 612eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(1); 613326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 614326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira case ComposeActivity.FORWARD: 615eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira actionBar.setSelectedNavigationItem(2); 616326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira break; 617326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 6186349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 619fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME, 620fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME); 621fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira actionBar.setHomeButtonEnabled(true); 6226349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 6236349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira 62446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void initFromRefMessage(int action, String recipientAddress) { 6258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setSubject(mRefMessage, action); 6268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Setup recipients 6278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == FORWARD) { 6288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mForward = true; 6298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initRecipientsFromRefMessage(recipientAddress, mRefMessage, action); 6318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initBodyFromRefMessage(mRefMessage, action); 6328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (action == ComposeActivity.FORWARD || mAttachmentsChanged) { 6338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initAttachments(mRefMessage); 6346349a043bce28ec999d72635222ae0eb576eb9cdMindy Pereira } 6358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira updateHideOrShowCcBcc(); 636c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 637c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira 638bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void initFromMessage(Message message) { 639bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook LogUtils.d(LOG_TAG, "Intializing draft from previous draft message"); 640bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 641bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraft = message; 642bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mDraftId = message.id; 643bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mSubject.setText(message.subject); 644bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mForward = message.draftType == UIProvider.DraftType.FORWARD; 645bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook final List<String> toAddresses = Arrays.asList(message.getToAddresses()); 646bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addToAddresses(toAddresses); 647bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addCcAddresses(Arrays.asList(message.getCcAddresses()), toAddresses); 648bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addBccAddresses(Arrays.asList(message.getBccAddresses())); 6492421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (message.hasAttachments) { 6502421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira List<Attachment> attachments = message.getAttachments(); 6512421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira for (Attachment a : attachments) { 6522421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(a.uri); 6532421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 6542421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 655bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 656bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // Set the body 657bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook if (!TextUtils.isEmpty(message.bodyHtml)) { 658bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mBodyView.setText(Html.fromHtml(message.bodyHtml)); 659bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } else { 660bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook mBodyView.setText(message.bodyText); 661bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 662bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 663bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // TODO: load attachments from the previous message 664bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // TODO: set the from address spinner to the right from account 665bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook // TODO: initialize quoted text value 666bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 667bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 6688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 6698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Fill all the widgets with the content found in the Intent Extra, if any. 6708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Also apply the same style to all widgets. Note: if initFromExtras is 6718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * called as a result of switching between reply, reply all, and forward per 6728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * the latest revision of Gmail, and the user has already made changes to 6738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * attachments on a previous incarnation of the message (as a reply, reply 6748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * all, or forward), the original attachments from the message will not be 6758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * re-instantiated. The user's changes will be respected. This follows the 6768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * web gmail interaction. 6778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 6788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromExtras(Intent intent) { 6798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // If we were invoked with a SENDTO intent, the value 6818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // should take precedence 6828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final Uri dataUri = intent.getData(); 6838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (dataUri != null) { 6848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (MAIL_TO.equals(dataUri.getScheme())) { 6858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromMailTo(dataUri.toString()); 6868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 6870b4f28ed53a7f1617dadf3b34de8c743a1733ce5Mindy Pereira if (!mAccount.composeIntentUri.equals(dataUri)) { 6888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String toText = dataUri.getSchemeSpecificPart(); 6898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (toText != null) { 6908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mTo.setText(""); 6918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(toText.split(","))); 6928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 6968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 6978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String[] extraStrings = intent.getStringArrayExtra(Intent.EXTRA_EMAIL); 6988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 6998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(extraStrings)); 7008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_CC); 7028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 7038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(extraStrings), null); 7048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira extraStrings = intent.getStringArrayExtra(Intent.EXTRA_BCC); 7068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraStrings != null) { 7078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(extraStrings)); 7088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String extraString = intent.getStringExtra(Intent.EXTRA_SUBJECT); 7118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extraString != null) { 7128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(extraString); 7138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (String extra : ALL_EXTRAS) { 7168eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (intent.hasExtra(extra)) { 7178eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String value = intent.getStringExtra(extra); 7188eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (EXTRA_TO.equals(extra)) { 7198eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(value.split(","))); 7208eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_CC.equals(extra)) { 7218eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(value.split(",")), null); 7228eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BCC.equals(extra)) { 7238eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(value.split(","))); 7248eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_SUBJECT.equals(extra)) { 7258eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(value); 7268eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else if (EXTRA_BODY.equals(extra)) { 7278eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(value, true /* with signature */); 7288eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7298eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7308eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7318eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7328eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Bundle extras = intent.getExtras(); 7338eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (extras != null) { 7348eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira final String action = intent.getAction(); 7358eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira CharSequence text = extras.getCharSequence(Intent.EXTRA_TEXT); 7368eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (text != null) { 7378eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(text, true /* with signature */); 7388eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7398eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7408eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7418eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira updateHideOrShowCcBcc(); 7428eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7438eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7448eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira @VisibleForTesting 7458eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira protected String decodeEmailInUri(String s) throws UnsupportedEncodingException { 7468eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: handle the case where there are spaces in the display name as well as the email 7478eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // such as "Guy with spaces <guy+with+spaces@gmail.com>" as they it could be encoded 7488eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // ambiguously. 7498eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7508eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Since URLDecode.decode changes + into ' ', and + is a valid 7518eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // email character, we need to find/ replace these ourselves before 7528eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // decoding. 7538eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String replacePlus = s.replace("+", "%2B"); 7548eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira return URLDecoder.decode(replacePlus, UTF8_ENCODING_NAME); 7558eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7568eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7578eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira /** 7588eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * Initialize the compose view from a String representing a mailTo uri. 7598eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira * @param mailToString The uri as a string. 7608eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira */ 7618eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira public void initFromMailTo(String mailToString) { 7628eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // We need to disguise this string as a URI in order to parse it 7638eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // TODO: Remove this hack when http://b/issue?id=1445295 gets fixed 7648eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira Uri uri = Uri.parse("foo://" + mailToString); 7658eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int index = mailToString.indexOf("?"); 7668eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira int length = "mailto".length() + 1; 7678eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira String to; 7688eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 7698eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Extract the recipient after mailto: 7708eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (index == -1) { 7718eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length)); 7728eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 7738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira to = decodeEmailInUri(mailToString.substring(length, index)); 7748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(to.split(" ,"))); 7768eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 7778eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (LogUtils.isLoggable(LOG_TAG, LogUtils.VERBOSE)) { 7788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding '%s'", e.getMessage(), mailToString); 7798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 7808eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, e, "Exception while decoding mailto address"); 7818eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7828eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 7838eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7848eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> cc = uri.getQueryParameters("cc"); 7858eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddresses(Arrays.asList(cc.toArray(new String[cc.size()])), null); 7868eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7878eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> otherTo = uri.getQueryParameters("to"); 7888eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addToAddresses(Arrays.asList(otherTo.toArray(new String[otherTo.size()]))); 7898eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7908eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> bcc = uri.getQueryParameters("bcc"); 7918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addBccAddresses(Arrays.asList(bcc.toArray(new String[bcc.size()]))); 7928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 7938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> subject = uri.getQueryParameters("subject"); 7948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (subject.size() > 0) { 7958eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 7968eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira mSubject.setText(URLDecoder.decode(subject.get(0), UTF8_ENCODING_NAME)); 7978eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 7988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding subject '%s'", 7998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira e.getMessage(), subject); 8008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira List<String> body = uri.getQueryParameters("body"); 8048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (body.size() > 0) { 8058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira try { 8068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira setBody(URLDecoder.decode(body.get(0), UTF8_ENCODING_NAME), 8078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira true /* with signature */); 8088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } catch (UnsupportedEncodingException e) { 8098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira LogUtils.e(LOG_TAG, "%s while decoding body '%s'", e.getMessage(), body); 8108eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8118eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8128eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8138eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira updateHideOrShowCcBcc(); 8148eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 8158eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira 8163ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void initAttachments(Message refMessage) { 8177a07fb4955e34250225287212b07d1b6f12bf671Mindy Pereira mAttachmentsView.addAttachments(mAccount, refMessage); 818eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 819eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 820f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook private void initAttachmentsFromIntent(Intent intent) { 82103ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook Bundle extras = intent.getExtras(); 82203ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook if (extras == null) { 82303ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook extras = Bundle.EMPTY; 82403ee971afd8d766dea81b72fe77593e3be3ab798Paul Westbrook } 825f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final String action = intent.getAction(); 826f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (!mAttachmentsChanged) { 827f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long totalSize = 0; 828f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (extras.containsKey(EXTRA_ATTACHMENTS)) { 829f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook String[] uris = (String[]) extras.getSerializable(EXTRA_ATTACHMENTS); 830f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (String uriString : uris) { 831f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = Uri.parse(uriString); 832f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 833f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 834f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook size = mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */, 835f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook true /* local file */); 836f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 837f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 838f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 839f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 840f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 841f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 842f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 843f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 844f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) { 845f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); 846f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 847f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 848f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook size = mAttachmentsView.addAttachment(mAccount, uri, false /* doSave */, 849f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook true /* local file */); 850f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 851f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, so just 852f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // exit. 853f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 854f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 855f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 856f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 857f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 858f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (Intent.ACTION_SEND_MULTIPLE.equals(action) 859f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook && extras.containsKey(Intent.EXTRA_STREAM)) { 860f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); 861f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook for (Parcelable uri : uris) { 862f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook long size = 0; 863f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook try { 864bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook size = mAttachmentsView.addAttachment(mAccount, (Uri) uri, 865f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook false /* doSave */, true /* local file */); 866f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } catch (AttachmentFailureException e) { 867f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // A toast has already been shown to the user, 868f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook // just break out of the loop. 869f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook LogUtils.e(LOG_TAG, e, "Error adding attachment"); 870f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 871f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook totalSize += size; 872f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 873f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 874f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 875f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook if (totalSize > 0) { 876f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook mAttachmentsChanged = true; 877f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook updateSaveUi(); 878f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 879f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 880f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook } 881f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 882f97588bd03fdcd318e24a9d74a283e73d1fbd37cPaul Westbrook 8833ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void initBodyFromRefMessage(Message refMessage, int action) { 8849932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (action == REPLY || action == REPLY_ALL || action == FORWARD) { 8859932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mQuotedTextView.setQuotedText(action, refMessage, action != FORWARD); 8869932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } 88746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 88846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 88946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira private void updateHideOrShowCcBcc() { 890ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 891a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira boolean ccVisible = !TextUtils.isEmpty(mCc.getText()); 892a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira boolean bccVisible = !TextUtils.isEmpty(mBcc.getText()); 893a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (ccVisible || bccVisible) { 894a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(false, ccVisible, bccVisible); 895a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 896ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 897ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!mCc.isShown() || !mBcc.isShown()) { 898ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.VISIBLE); 899ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setText(getString(!mCc.isShown() ? R.string.add_cc_label 900ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 901ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 902ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 903ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 904ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 90546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 90646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 907013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira /** 908013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * Add attachment and update the compose area appropriately. 909013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira * @param data 910013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira */ 911013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void addAttachmentAndUpdateView(Intent data) { 9122421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira addAttachmentAndUpdateView(data != null ? data.getData() : (Uri) null); 9132421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 9142421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira 9152421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira public void addAttachmentAndUpdateView(Uri uri) { 9162421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira if (uri == null) { 9172421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira return; 9182421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira } 919013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira try { 9202421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira long size = mAttachmentsView.addAttachment(mAccount, uri, 9212421dc8d6d0b4c727ab7ab0e5ce730f415089e86Mindy Pereira false /* doSave */, 922f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira true /* local file */); 9239932dee248718d2cec993d93b5115973d1389d0aMindy Pereira if (size > 0) { 9249932dee248718d2cec993d93b5115973d1389d0aMindy Pereira mAttachmentsChanged = true; 9259932dee248718d2cec993d93b5115973d1389d0aMindy Pereira updateSaveUi(); 926013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 9279932dee248718d2cec993d93b5115973d1389d0aMindy Pereira } catch (AttachmentFailureException e) { 9289932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // A toast has already been shown to the user, no need to do 9299932dee248718d2cec993d93b5115973d1389d0aMindy Pereira // anything. 9309932dee248718d2cec993d93b5115973d1389d0aMindy Pereira LogUtils.e(LOG_TAG, e, "Error adding attachment"); 931013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 932013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 933013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 9343ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initRecipientsFromRefMessage(String recipientAddress, Message refMessage, 93546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira int action) { 9364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Don't populate the address if this is a forward. 9374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (action == ComposeActivity.FORWARD) { 9384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 9394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 94033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira initReplyRecipients(mAccount.name, refMessage, action); 9414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 943818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira @VisibleForTesting 9443ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira void initReplyRecipients(String account, Message refMessage, int action) { 9454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // This is the email address of the current user, i.e. the one composing 9464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the reply. 9474a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String accountEmail = Address.getEmailAddress(account).getAddress(); 9483ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String fromAddress = refMessage.from; 9493ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String[] sentToAddresses = Utils.splitCommaSeparatedString(refMessage.to); 9503ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String replytoAddress = refMessage.replyTo; 951a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira final Collection<String> toAddresses; 9524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9534a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // If this is a reply, the Cc list is empty. If this is a reply-all, the 9544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Cc list is the union of the To and Cc recipients of the original 9554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, excluding the current user's email address and any addresses 956a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira // already on the To list. 957a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (action == ComposeActivity.REPLY) { 9583ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 9593ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 960a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira addToAddresses(toAddresses); 961a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } else if (action == ComposeActivity.REPLY_ALL) { 9624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira final Set<String> ccAddresses = Sets.newHashSet(); 9633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses = initToRecipients(account, accountEmail, fromAddress, replytoAddress, 9643ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira new String[0]); 965154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira addToAddresses(toAddresses); 9664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addRecipients(accountEmail, ccAddresses, sentToAddresses); 9673ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira addRecipients(accountEmail, ccAddresses, 9683ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira Utils.splitCommaSeparatedString(refMessage.cc)); 9694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addCcAddresses(ccAddresses, toAddresses); 9704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9724a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addToAddresses(Collection<String> addresses) { 9744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressesToList(addresses, mTo); 9754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9774a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addCcAddresses(Collection<String> addresses, Collection<String> toAddresses) { 9788eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira addCcAddressesToList(tokenizeAddressList(addresses), 9798eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira toAddresses != null ? tokenizeAddressList(toAddresses) : null, mCc); 9804a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9814a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 982bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook private void addBccAddresses(Collection<String> addresses) { 983bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook addAddressesToList(addresses, mBcc); 984bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook } 985bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook 9864a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 9874a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected void addCcAddressesToList(List<Rfc822Token[]> addresses, 9884a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> compareToList, RecipientEditTextView list) { 9894a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira String address; 9904a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 9918eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (compareToList == null) { 9928eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 9938eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 9948eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 9954a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(address + END_TOKEN); 9964a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9974a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 9988eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } else { 9998eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira HashSet<String> compareTo = convertToHashSet(compareToList); 10008eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (Rfc822Token[] tokens : addresses) { 10018eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira for (int i = 0; i < tokens.length; i++) { 10028eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira address = tokens[i].toString(); 10038eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Check if this is a duplicate: 10048eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (!compareTo.contains(tokens[i].getAddress())) { 10058eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira // Get the address here 10068eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira list.append(address + END_TOKEN); 10078eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10088eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10098eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 10104a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10114a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10124a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10134a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private HashSet<String> convertToHashSet(List<Rfc822Token[]> list) { 10144a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira HashSet<String> hash = new HashSet<String>(); 10154a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (Rfc822Token[] tokens : list) { 10164a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 10174a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira hash.add(tokens[i].getAddress()); 10184a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10194a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10204a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return hash; 10214a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10224a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10234a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected List<Rfc822Token[]> tokenizeAddressList(Collection<String> addresses) { 10244a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 10254a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira List<Rfc822Token[]> tokenized = new ArrayList<Rfc822Token[]>(); 10264a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10274a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address: addresses) { 10284a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira tokenized.add(Rfc822Tokenizer.tokenize(address)); 10294a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10304a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return tokenized; 10314a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10324a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10334a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 10344a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira void addAddressesToList(Collection<String> addresses, RecipientEditTextView list) { 10354a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String address : addresses) { 10364a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira addAddressToList(address, list); 10374a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10384a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10394a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10404a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private void addAddressToList(String address, RecipientEditTextView list) { 10414a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (address == null || list == null) 10424a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return; 10434a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10444a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address); 10454a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10464a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (int i = 0; i < tokens.length; i++) { 10474a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira list.append(tokens[i] + END_TOKEN); 10484a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10494a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10504a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10514a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira @VisibleForTesting 10524a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira protected Collection<String> initToRecipients(String account, String accountEmail, 10533ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String senderAddress, String replyToAddress, String[] inToAddresses) { 10544a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // The To recipient is the reply-to address specified in the original 10554a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // message, unless it is: 10564a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // the current user OR a custom from of the current user, in which case 10574a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // it's the To recipient list of the original message. 10584a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // OR missing, in which case use the sender of the original message 10594a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira Set<String> toAddresses = Sets.newHashSet(); 10603ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira if (!TextUtils.isEmpty(replyToAddress)) { 10613ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(replyToAddress); 10624a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } else { 10633ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira toAddresses.add(senderAddress); 10644a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10654a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira return toAddresses; 10664a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10674a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira 10684a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira private static void addRecipients(String account, Set<String> recipients, String[] addresses) { 10694a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira for (String email : addresses) { 10704a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // Do not add this account, or any of the custom froms, to the list 10714a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira // of recipients. 10724a20b708dd9ff3fb2b96f29b0b59012194c6fa34Mindy Pereira final String recipientAddress = Address.getEmailAddress(email).getAddress(); 10734a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira if (!account.equalsIgnoreCase(recipientAddress)) { 10744a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira recipients.add(email.replace("\"\"", "")); 10754a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 10764a27ea93a9eb05558f97a05a5342afb10f3d92ddMindy Pereira } 107746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 107846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 10793ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira private void setSubject(Message refMessage, int action) { 10803ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String subject = refMessage.subject; 108146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String prefix; 108246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira String correctedSubject = null; 108346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (action == ComposeActivity.COMPOSE) { 108446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = ""; 108546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else if (action == ComposeActivity.FORWARD) { 108646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.forward_subject_label); 108746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 108846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira prefix = getString(R.string.reply_subject_label); 108946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 109046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 109146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira // Don't duplicate the prefix 109246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (subject.toLowerCase().startsWith(prefix.toLowerCase())) { 109346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = subject; 109446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 109546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira correctedSubject = String 109646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira .format(getString(R.string.formatted_subject), prefix, subject); 109746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 109846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira mSubject.setText(correctedSubject); 109946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 110046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 1101818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void initRecipients() { 1102818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mTo); 1103818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mCc); 1104818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira setupRecipients(mBcc); 1105eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 1106eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 1107818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira private void setupRecipients(RecipientEditTextView view) { 1108679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook view.setAdapter(new RecipientAdapter(this, mAccount)); 1109c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira view.setTokenizer(new Rfc822Tokenizer()); 111082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mValidator == null) { 1111679a8cc895ec75d3b578dbc77db1e9c04dd7f8b0Paul Westbrook final String accountName = mAccount.name; 111233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira int offset = accountName.indexOf("@") + 1; 111333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira String account = accountName; 1114c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira if (offset > -1) { 111533fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira account = account.substring(accountName.indexOf("@") + 1); 1116c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 111782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValidator = new Rfc822Validator(account); 1118c17d073dd43871df36ea70b3dea55963bdb98384Mindy Pereira } 111982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira view.setValidator(mValidator); 11208e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 11218e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira 11228e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira @Override 11238e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira public void onClick(View v) { 11248e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira int id = v.getId(); 11258e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira switch (id) { 1126a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira case R.id.add_cc_bcc: 11278e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Verify that cc/ bcc aren't showing. 11288e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira // Animate in cc/bcc. 1129a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira showCcBccViews(); 11308e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira break; 11311f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.add_attachment: 11321f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira doAttach(); 11331f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 11348e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 11358e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira } 1136b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1137b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1138b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onCreateOptionsMenu(Menu menu) { 1139b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira super.onCreateOptionsMenu(menu); 1140b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira MenuInflater inflater = getMenuInflater(); 1141b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira inflater.inflate(R.menu.compose_menu, menu); 114282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = menu.findItem(R.id.save); 114382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend = menu.findItem(R.id.send); 1144b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return true; 1145b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1146b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira 1147b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira @Override 1148ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira public boolean onPrepareOptionsMenu(Menu menu) { 1149ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira MenuItem ccBcc = menu.findItem(R.id.add_cc_bcc); 1150818143e2163648acc0c91f123b84777d65cd70cfMindy Pereira if (ccBcc != null && mCc != null) { 1151ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira // Its possible there is a menu item OR a button. 1152ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean ccFieldVisible = mCc.isShown(); 1153ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira boolean bccFieldVisible = mBcc.isShown(); 1154ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (!ccFieldVisible || !bccFieldVisible) { 1155ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(true); 1156ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setTitle(getString(!ccFieldVisible ? R.string.add_cc_label 1157ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira : R.string.add_bcc_label)); 1158ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } else { 1159ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira ccBcc.setVisible(false); 1160ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1161ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 116275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (mSave != null) { 116375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mSave.setEnabled(shouldSave()); 116475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 1165ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira return true; 1166ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1167ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1168ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira @Override 1169b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira public boolean onOptionsItemSelected(MenuItem item) { 1170b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira int id = item.getItemId(); 117175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira boolean handled = true; 1172b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira switch (id) { 11737b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira case R.id.add_attachment: 1174013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira doAttach(); 11757b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira break; 1176ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira case R.id.add_cc_bcc: 1177ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira showCcBccViews(); 1178b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira break; 117933fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.save: 1180eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSave(true, false); 118133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 118233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira case R.id.send: 118333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira doSend(); 118475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira break; 1185efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira case R.id.discard: 1186efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira doDiscard(); 1187efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira break; 11881f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira case R.id.settings: 11891f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira Utils.showSettings(this, mAccount); 11901f93668e1186d48b507207841c1ca0529c3de292Mindy Pereira break; 1191fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case android.R.id.home: 1192fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira finish(); 1193fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1194fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.help_info_menu_item: 1195fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira // TODO: enable context sensitive help 1196498e76d7efccc92386fe57c65a2ef8d5a0172604Paul Westbrook Utils.showHelp(this, mAccount, null); 1197fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 1198fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira case R.id.feedback_menu_item: 1199fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira Utils.sendFeedback(this, mAccount); 1200fbe4019a262f6b1934a44e598009ae63dc5745eeMindy Pereira break; 120175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira default: 120275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira handled = false; 120333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira break; 1204b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1205b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira return !handled ? super.onOptionsItemSelected(item) : handled; 1206b47f3e286bcf78e85ab2d3389e38e99020d0634fMindy Pereira } 1207326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 120833fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira private void doSend() { 120982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira sendOrSaveWithSanityChecks(false, true, false); 121033fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 121133fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 1212eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void doSave(boolean showToast, boolean resetIME) { 1213eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira sendOrSaveWithSanityChecks(true, showToast, false); 1214eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (resetIME) { 1215eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // Clear the IME composing suggestions from the body. 1216eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira BaseInputConnection.removeComposingSpans(mBodyView.getEditableText()); 1217eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 121882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 121982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 122082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ interface SendOrSaveCallback { 122182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask); 12227ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, Message message); 12237ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage(); 122482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void sendOrSaveFinished(SendOrSaveTask sendOrSaveTask, boolean success); 122582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 122682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 122782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ static class SendOrSaveTask implements Runnable { 122882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final Context mContext; 122982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private final SendOrSaveCallback mSendOrSaveCallback; 123082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @VisibleForTesting 123182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final SendOrSaveMessage mSendOrSaveMessage; 123282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 123382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public SendOrSaveTask(Context context, SendOrSaveMessage message, 123482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira SendOrSaveCallback callback) { 123582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext = context; 123682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback = callback; 123782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveMessage = message; 123882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 123982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 124082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 124182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void run() { 12427ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira final SendOrSaveMessage sendOrSaveMessage = mSendOrSaveMessage; 124382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 124492551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount selectedAccount = sendOrSaveMessage.mAccount; 12457ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message = mSendOrSaveCallback.getMessage(); 12467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira long messageId = message != null ? message.id : UIProvider.INVALID_MESSAGE_ID; 124782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If a previous draft has been saved, in an account that is different 124882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // than what the user wants to send from, remove the old draft, and treat this 124982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // as a new message 12507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!selectedAccount.equals(sendOrSaveMessage.mAccount)) { 125182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageId != UIProvider.INVALID_MESSAGE_ID) { 125282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentResolver resolver = mContext.getContentResolver(); 125382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 125482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira values.put(BaseColumns._ID, messageId); 125592551d057965689f1952faeb06763f0762bc717fMindy Pereira if (selectedAccount.account.expungeMessageUri != null) { 125692551d057965689f1952faeb06763f0762bc717fMindy Pereira resolver.update(selectedAccount.account.expungeMessageUri, values, null, 1257eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira null); 1258cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 1259cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp) delete the conversation. 1260eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 126182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // reset messageId to 0, so a new message will be created 126282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira messageId = UIProvider.INVALID_MESSAGE_ID; 126382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 126482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 126582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 126682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final long messageIdToSave = messageId; 126782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (messageIdToSave != UIProvider.INVALID_MESSAGE_ID) { 12687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues.put(BaseColumns._ID, messageIdToSave); 126982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mContext.getContentResolver().update( 12707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Uri.parse(sendOrSaveMessage.mSave ? message.saveUri : message.sendUri), 12717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sendOrSaveMessage.mValues, null, null); 127282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } else { 12737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira ContentResolver resolver = mContext.getContentResolver(); 127492551d057965689f1952faeb06763f0762bc717fMindy Pereira Uri messageUri = resolver 127592551d057965689f1952faeb06763f0762bc717fMindy Pereira .insert(sendOrSaveMessage.mSave ? selectedAccount.account.saveDraftUri 127692551d057965689f1952faeb06763f0762bc717fMindy Pereira : selectedAccount.account.sendMessageUri, 127792551d057965689f1952faeb06763f0762bc717fMindy Pereira sendOrSaveMessage.mValues); 12787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sendOrSaveMessage.mSave && messageUri != null) { 12797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Cursor messageCursor = resolver.query(messageUri, 12807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira UIProvider.MESSAGE_PROJECTION, null, null, null); 1281ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor != null) { 1282ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook try { 1283ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook if (messageCursor.moveToFirst()) { 1284ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // Broadcast notification that a new message has 1285ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook // been allocated 1286ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook mSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, 1287ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook new Message(messageCursor)); 1288ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 1289ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } finally { 1290ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook messageCursor.close(); 1291ba5584836c0a63c8dac96b10b569465bd56d5f7aPaul Westbrook } 12927ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 12937ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 129482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 129582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 12967ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (!sendOrSaveMessage.mSave) { 129782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 12987ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.TO)); 129982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 13007ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.CC)); 130182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira UIProvider.incrementRecipientsTimesContacted(mContext, 13027ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira (String) sendOrSaveMessage.mValues.get(UIProvider.MessageColumns.BCC)); 130382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 130482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSendOrSaveCallback.sendOrSaveFinished(SendOrSaveTask.this, true); 130582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 130682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 130782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 130882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Array of the outstanding send or save tasks. Access is synchronized 130982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // with the object itself 131082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /* package for testing */ 131182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ArrayList<SendOrSaveTask> mActiveTasks = Lists.newArrayList(); 131282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRequestId; 1313bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String mSignature; 131482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 131582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /*package*/ static class SendOrSaveMessage { 131692551d057965689f1952faeb06763f0762bc717fMindy Pereira final ReplyFromAccount mAccount; 131782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final ContentValues mValues; 13183ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira final String mRefMessageId; 131982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final boolean mSave; 132082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira final int mRequestId; 132182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 132292551d057965689f1952faeb06763f0762bc717fMindy Pereira public SendOrSaveMessage(ReplyFromAccount account, ContentValues values, 13233ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira String refMessageId, boolean save) { 132482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mAccount = account; 132582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mValues = values; 132682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRefMessageId = refMessageId; 132782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave = save; 132882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRequestId = mValues.hashCode() ^ hashCode(); 132982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 133082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 133182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int requestId() { 133282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mRequestId; 133382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 133482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 133582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 133682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 133782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the to recipients. 133882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 133982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getToAddresses() { 134082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mTo); 134182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 134282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 134382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 134482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the cc recipients. 134582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 134682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getCcAddresses() { 134782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mCc); 134882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 134982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 135082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 135182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Get the bcc recipients. 135282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 135382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getBccAddresses() { 135482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return getAddressesFromList(mBcc); 135582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 135682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 135782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public String[] getAddressesFromList(RecipientEditTextView list) { 135882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (list == null) { 135982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return new String[0]; 136082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 136182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(list.getText()); 136282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira int count = tokens.length; 136382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira String[] result = new String[count]; 136482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (int i = 0; i < count; i++) { 136582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira result[i] = tokens[i].toString(); 136682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 136782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return result; 136882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 136982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 137082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 137182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Check for invalid email addresses. 137282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param to String array of email addresses to check. 137382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param wrongEmailsOut Emails addresses that were invalid. 137482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 137582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void checkInvalidEmails(String[] to, List<String> wrongEmailsOut) { 137682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira for (String email : to) { 137782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (!mValidator.isValid(email)) { 137882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira wrongEmailsOut.add(email); 137982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 138082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 138182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 138282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 138382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 138482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Show an error because the user has entered an invalid recipient. 138582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param message 138682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 138782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void showRecipientErrorDialog(String message) { 138882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Only 1 invalid recipients error dialog should be allowed up at a 138982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // time. 139082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mRecipientErrorDialog != null) { 139182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog.dismiss(); 139282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 139382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = new AlertDialog.Builder(this).setMessage(message).setTitle( 139482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.recipient_error_dialog_title) 139582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 139682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setCancelable(false) 139782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira .setPositiveButton( 139882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira R.string.ok, new Dialog.OnClickListener() { 139982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 140082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // after the user dismisses the recipient error 140182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // dialog we want to make sure to refocus the 140282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // recipient to field so they can fix the issue 140382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // easily 140482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mTo != null) { 140582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTo.requestFocus(); 140682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 140782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mRecipientErrorDialog = null; 140882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 140982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira }).show(); 141082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 141182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 141282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 141382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Update the state of the UI based on whether or not the current draft 141482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * needs to be saved and the message is not empty. 141582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 1416eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void updateSaveUi() { 141782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 141882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled((shouldSave() && !isBlank())); 141982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 142082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 142182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 142282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 142382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Returns true if we need to save the current draft. 142482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 142582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private boolean shouldSave() { 14267ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 142782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // The message should only be saved if: 142882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // It hasn't been sent AND 142982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Some text has been added to the message OR 143082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // an attachment has been added or removed 1431eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return (mTextChanged || mAttachmentsChanged || 143282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira (mReplyFromChanged && !isBlank())); 143382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 143482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 143582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 143682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1437bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * Check if all fields are blank. 143882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @return boolean 143982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 144082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public boolean isBlank() { 144182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira return mSubject.getText().length() == 0 1442bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && (mBodyView.getText().length() == 0 || getSignatureStartPosition(mSignature, 1443bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira mBodyView.getText().toString()) == 0) 1444bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mTo.length() == 0 1445bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mCc.length() == 0 && mBcc.length() == 0 1446bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && mAttachmentsView.getAttachments().size() == 0; 1447bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1448bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1449bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira @VisibleForTesting 1450bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira protected int getSignatureStartPosition(String signature, String bodyText) { 1451bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int startPos = -1; 1452bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1453bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (TextUtils.isEmpty(signature) || TextUtils.isEmpty(bodyText)) { 1454bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 1455bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1456bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1457bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int bodyLength = bodyText.length(); 1458bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int signatureLength = signature.length(); 1459bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String printableVersion = convertToPrintableSignature(signature); 1460bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira int printableLength = printableVersion.length(); 1461bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1462bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (bodyLength >= printableLength 1463bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - printableLength) 1464bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(printableVersion)) { 1465bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - printableLength; 1466bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } else if (bodyLength >= signatureLength 1467bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira && bodyText.substring(bodyLength - signatureLength) 1468bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira .equals(signature)) { 1469bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira startPos = bodyLength - signatureLength; 1470bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1471bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return startPos; 147282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 147382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 147482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 147582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Allows any changes made by the user to be ignored. Called when the user 147682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * decides to discard a draft. 147782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 147882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void discardChanges() { 147982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mTextChanged = false; 1480eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = false; 148182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mReplyFromChanged = false; 148233fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira } 148333fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereira 148482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 1485181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param body 1486181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param save 1487181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @param showToast 1488181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return Whether the send or save succeeded. 1489181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1490181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean sendOrSaveWithSanityChecks(final boolean save, final boolean showToast, 1491181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira final boolean orientationChanged) { 1492181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1493181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Editable body = mBodyView.getEditableText(); 1494181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1495181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1496181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1497181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1498181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1499181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1500181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1501181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1502181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1503181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send to nobody (but it's okay to save a message 1504181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // with no recipients) 1505181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save && (to.length == 0 && cc.length == 0 && bcc.length == 0)) { 1506181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(getString(R.string.recipient_needed)); 1507181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1508181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1509181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1510181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira List<String> wrongEmails = new ArrayList<String>(); 1511181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1512181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(to, wrongEmails); 1513181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(cc, wrongEmails); 1514181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira checkInvalidEmails(bcc, wrongEmails); 1515181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1516181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1517181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't let the user send an email with invalid recipients 1518181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (wrongEmails.size() > 0) { 1519181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String errorText = String.format(getString(R.string.invalid_recipient), 1520181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira wrongEmails.get(0)); 1521181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showRecipientErrorDialog(errorText); 1522181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return false; 1523181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1524181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1525181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 1526181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public void onClick(DialogInterface dialog, int which) { 1527181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(mBodyView.getEditableText(), save, showToast, orientationChanged); 1528181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1529181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1530181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1531181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Show a warning before sending only if there are no attachments. 1532181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1533181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mAttachmentsView.getAttachments().isEmpty() && showEmptyTextWarnings()) { 1534181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptySubject = isSubjectEmpty(); 1535181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean emptyBody = TextUtils.getTrimmedLength(body) == 0; 1536181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1537181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // A warning about an empty body may not be warranted when 1538181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // forwarding mails, since a common use case is to forward 1539181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // quoted text and not append any more text. 1540181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean warnAboutEmptyBody = emptyBody && (!mForward || isBodyEmpty()); 1541181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1542181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // When we bring up a dialog warning the user about a send, 1543181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // assume that they accept sending the message. If they do not, 1544181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the dialog listener is required to enable sending again. 1545181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptySubject) { 1546181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_subject, listener); 1547181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1548181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1549181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1550181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (warnAboutEmptyBody) { 1551181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message_with_no_body, listener); 1552181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1553181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1554181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1555181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Ask for confirmation to send (if always required) 1556181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showSendConfirmation()) { 1557181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira showSendConfirmDialog(R.string.confirm_send_message, listener); 1558181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1559181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1560181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1561181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1562181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sendOrSave(body, save, showToast, false); 1563181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return true; 1564181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1565181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1566181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1567181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether warnings should be shown for empty 1568181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * subject and body fields 1569181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1570181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be shown for empty text fields 1571181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1572181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showEmptyTextWarnings() { 1573181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mAttachmentsView.getAttachments().size() == 0; 1574181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1575181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1576181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1577181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns a boolean indicating whether the user should confirm each send 1578181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1579181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return True if a warning should be on each send 1580181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1581181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira protected boolean showSendConfirmation() { 1582181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return mCachedSettings != null ? mCachedSettings.confirmSend : false; 1583181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1584181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1585181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void showSendConfirmDialog(int messageId, DialogInterface.OnClickListener listener) { 1586181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendConfirmDialog != null) { 1587181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog.dismiss(); 1588181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = null; 1589181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1590181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendConfirmDialog = new AlertDialog.Builder(this).setMessage(messageId) 1591181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setTitle(R.string.confirm_send_title) 1592181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setIconAttribute(android.R.attr.alertDialogIcon) 1593181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setPositiveButton(R.string.send, listener) 1594181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira .setNegativeButton(R.string.cancel, this).setCancelable(false).show(); 1595181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1596181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1597181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1598181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Returns whether the ComposeArea believes there is any text in the body of 1599181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * the composition. TODO: When ComposeArea controls the Body as well, add 1600181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * that here. 1601181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1602181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isBodyEmpty() { 1603181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return !mQuotedTextView.isTextIncluded(); 1604181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1605181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1606181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1607181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Test to see if the subject is empty. 1608181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * 1609181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * @return boolean. 1610181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1611181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: this will likely go away when composeArea.focus() is implemented 1612181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // after all the widget control is moved over. 1613181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira public boolean isSubjectEmpty() { 1614181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return TextUtils.getTrimmedLength(mSubject.getText()) == 0; 1615181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1616181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1617181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /* package */ 161892551d057965689f1952faeb06763f0762bc717fMindy Pereira static int sendOrSaveInternal(Context context, final ReplyFromAccount replyFromAccount, 161992551d057965689f1952faeb06763f0762bc717fMindy Pereira String fromAddress, final Spanned body, final String[] to, final String[] cc, 162092551d057965689f1952faeb06763f0762bc717fMindy Pereira final String[] bcc, final String subject, final CharSequence quotedText, 162192551d057965689f1952faeb06763f0762bc717fMindy Pereira final List<Attachment> attachments, final Message refMessage, 162292551d057965689f1952faeb06763f0762bc717fMindy Pereira SendOrSaveCallback callback, Handler handler, boolean save, int composeMode) { 162329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira ContentValues values = new ContentValues(); 162429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 1625c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira String refMessageId = refMessage != null ? refMessage.uri.toString() : ""; 1626c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira 162729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putToAddresses(values, to); 162829ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putCcAddresses(values, cc); 162929ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putBccAddresses(values, bcc); 163029ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira 163192551d057965689f1952faeb06763f0762bc717fMindy Pereira MessageModification.putCustomFromAddress(values, replyFromAccount.address); 163292551d057965689f1952faeb06763f0762bc717fMindy Pereira 163329ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira MessageModification.putSubject(values, subject); 163429ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira String htmlBody = Html.toHtml(body); 163529ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira boolean includeQuotedText = !TextUtils.isEmpty(quotedText); 163629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira StringBuilder fullBody = new StringBuilder(htmlBody); 163729ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira if (includeQuotedText) { 1638e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // HTML gets converted to text for now 1639e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira final String text = quotedText.toString(); 1640e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira if (QuotedTextView.containsQuotedText(text)) { 1641e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira int pos = QuotedTextView.getQuotedTextOffset(text); 1642e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text.substring(0, pos)); 1643ffe6bb0e2af5a0d4e7a51bd060829a348b121da5Paul Westbrook MessageModification.putQuoteStartPos(values, fullBody.length()); 164412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putForward(values, composeMode == ComposeActivity.FORWARD); 1645e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira MessageModification.putAppendRefMessageContent(values, includeQuotedText); 164629ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } else { 1647e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira LogUtils.w(LOG_TAG, "Couldn't find quoted text"); 1648e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // This shouldn't happen, but just use what we have, 1649e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira // and don't do server-side expansion 1650e8caf1279a1c6ae720215405f678172a5cbf68d7Mindy Pereira fullBody.append(text); 165129ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 165229ef1b89b158281ffb693dd5f2c5291a894109fcMindy Pereira } 165312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira int draftType = -1; 165412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira switch (composeMode) { 165512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.COMPOSE: 165612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.COMPOSE; 165712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 165812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.REPLY: 165912575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.REPLY; 166012575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 166112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.REPLY_ALL: 166212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.REPLY_ALL; 166312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 166412575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira case ComposeActivity.FORWARD: 166512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira draftType = DraftType.FORWARD; 166612575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira break; 166712575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 166812575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putDraftType(values, draftType); 1669c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (refMessage != null) { 1670c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyHtml)) { 1671c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1672c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 1673c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira if (!TextUtils.isEmpty(refMessage.bodyText)) { 1674c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 1675c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } 1676c6f1e2a8690bd3d4722a2e9386cdc98691135063Mindy Pereira } else { 1677c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBodyHtml(values, fullBody.toString()); 1678c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira MessageModification.putBody(values, Html.fromHtml(fullBody.toString()).toString()); 1679c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira } 1680f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira MessageModification.putAttachments(values, attachments); 168112575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira if (!TextUtils.isEmpty(refMessageId)) { 168212575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira MessageModification.putRefMessageId(values, refMessageId); 168312575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira } 168482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 168592551d057965689f1952faeb06763f0762bc717fMindy Pereira SendOrSaveMessage sendOrSaveMessage = new SendOrSaveMessage(replyFromAccount, 1686181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira values, refMessageId, save); 1687181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveTask sendOrSaveTask = new SendOrSaveTask(context, sendOrSaveMessage, callback); 168882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1689181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira callback.initializeSendOrSave(sendOrSaveTask); 169082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1691181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Do the send/save action on the specified handler to avoid possible 1692181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // ANRs 1693181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handler.post(sendOrSaveTask); 169482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1695181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return sendOrSaveMessage.requestId(); 1696181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 169782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1698181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void sendOrSave(Spanned body, boolean save, boolean showToast, 1699181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira boolean orientationChanged) { 1700181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Check if user is a monkey. Monkeys can compose and hit send 1701181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // button but are not allowed to send anything off the device. 17023ae824c79ffba25b0cda8b0300f41a28cfbfca7fPaul Westbrook if (ActivityManager.isUserAMonkey()) { 1703181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira return; 1704181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 170582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1706181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String[] to, cc, bcc; 1707181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (orientationChanged) { 1708181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = cc = bcc = new String[0]; 1709181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } else { 1710181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira to = getToAddresses(); 1711181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira cc = getCcAddresses(); 1712181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira bcc = getBccAddresses(); 1713181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 171482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1715181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira SendOrSaveCallback callback = new SendOrSaveCallback() { 171682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private int mRestoredRequestId; 171782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 171882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void initializeSendOrSave(SendOrSaveTask sendOrSaveTask) { 1719181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mActiveTasks) { 1720181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira int numTasks = mActiveTasks.size(); 1721181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (numTasks == 0) { 1722181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Start service so we won't be killed if this app is 1723181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // put in the background. 1724181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startService(new Intent(ComposeActivity.this, EmptyService.class)); 1725181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1726181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1727181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mActiveTasks.add(sendOrSaveTask); 1728181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1729181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 1730181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira sTestSendOrSaveCallback.initializeSendOrSave(sendOrSaveTask); 1731181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1732181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 173382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 17347ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void notifyMessageIdAllocated(SendOrSaveMessage sendOrSaveMessage, 17357ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Message message) { 1736181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira synchronized (mDraftLock) { 1737181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraftId = message.id; 1738181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mDraft = message; 17397ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sRequestMessageIdMap != null) { 17407ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sRequestMessageIdMap.put(sendOrSaveMessage.requestId(), mDraftId); 17417ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 1742181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Cache request message map, in case the process is killed 1743181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira saveRequestMap(); 1744181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1745181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (sTestSendOrSaveCallback != null) { 17467ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.notifyMessageIdAllocated(sendOrSaveMessage, message); 1747181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1748181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 174982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 17507ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public Message getMessage() { 17517ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 17527ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira return mDraft; 17537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 17547ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 175582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 17567ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira public void sendOrSaveFinished(SendOrSaveTask task, boolean success) { 17577ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (success) { 17587ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Successfully sent or saved so reset change markers 17597ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira discardChanges(); 17607ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } else { 17617ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // A failure happened with saving/sending the draft 17627ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // TODO(pwestbro): add a better string that should be used 17637ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // when failing to send or save 17647ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira Toast.makeText(ComposeActivity.this, R.string.send_failed, Toast.LENGTH_SHORT) 17657ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira .show(); 17667ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 176782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 17687ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira int numTasks; 17697ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mActiveTasks) { 17707ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Remove the task from the list of active tasks 17717ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira mActiveTasks.remove(task); 17727ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira numTasks = mActiveTasks.size(); 17737ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 177482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 17757ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (numTasks == 0) { 17767ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira // Stop service so we can be killed. 17777ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira stopService(new Intent(ComposeActivity.this, EmptyService.class)); 17787ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 17797ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira if (sTestSendOrSaveCallback != null) { 17807ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira sTestSendOrSaveCallback.sendOrSaveFinished(task, success); 17817ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 17827ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira } 1783181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira }; 1784181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1785181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Get the selected account if the from spinner has been setup. 178692551d057965689f1952faeb06763f0762bc717fMindy Pereira ReplyFromAccount selectedAccount = mReplyFromAccount; 1787181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira String fromAddress = selectedAccount.name; 1788181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (selectedAccount == null || fromAddress == null) { 1789181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // We don't have either the selected account or from address, 1790181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // use mAccount. 179192551d057965689f1952faeb06763f0762bc717fMindy Pereira selectedAccount = mReplyFromAccount; 1792181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira fromAddress = mAccount.name; 1793181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1794181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1795181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mSendSaveTaskHandler == null) { 1796181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira HandlerThread handlerThread = new HandlerThread("Send Message Task Thread"); 1797181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira handlerThread.start(); 1798181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1799181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mSendSaveTaskHandler = new Handler(handlerThread.getLooper()); 1800181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1801181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 180292551d057965689f1952faeb06763f0762bc717fMindy Pereira mRequestId = sendOrSaveInternal(this, mReplyFromAccount, fromAddress, body, to, cc, 1803ffe6bb0e2af5a0d4e7a51bd060829a348b121da5Paul Westbrook bcc, mSubject.getText().toString(), mQuotedTextView.getQuotedTextIfIncluded(), 1804c203197908a95f707e93621e5eb5f0fb8bfc7d1fMindy Pereira mAttachmentsView.getAttachments(), mRefMessage, callback, 180512575866e5526e45eaf773c6c98c93c3a06fe156Mindy Pereira mSendSaveTaskHandler, save, mComposeMode); 1806181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1807181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (mRecipient != null && mRecipient.equals(mAccount.name)) { 1808181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mRecipient = selectedAccount.name; 1809181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1810b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(selectedAccount.account); 1811181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1812181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Don't display the toast if the user is just changing the orientation, 1813181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // but we still need to save the draft to the cursor because this is how we restore 1814181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // the attachments when the configuration change completes. 1815181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (showToast && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) { 1816181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.makeText(this, save ? R.string.message_saved : R.string.sending_message, 1817181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira Toast.LENGTH_LONG).show(); 1818181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1819181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1820181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Need to update variables here because the send or save completes 1821181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // asynchronously even though the toast shows right away. 1822181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira discardChanges(); 1823181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira updateSaveUi(); 1824181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1825181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // If we are sending, finish the activity 1826181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!save) { 1827181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira finish(); 1828181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1829181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 1830181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira 1831181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira /** 1832181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * Save the state of the request messageid map. This allows for the Gmail 1833181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * process to be killed, but and still allow for ComposeActivity instances 1834181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira * to be recreated correctly. 1835181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira */ 1836181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira private void saveRequestMap() { 1837181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: store the request map in user preferences. 1838181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 183982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 1840013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira public void doAttach() { 1841013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira Intent i = new Intent(Intent.ACTION_GET_CONTENT); 1842013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.addCategory(Intent.CATEGORY_OPENABLE); 1843181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (android.provider.Settings.System.getInt(getContentResolver(), 1844181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira UIProvider.getAttachmentTypeSetting(), 0) != 0) { 1845013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.setType("*/*"); 1846013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } else { 1847013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira i.setType("image/*"); 1848013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1849013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira mAddingAttachment = true; 1850181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira startActivityForResult(Intent.createChooser(i, getText(R.string.select_attachment_type)), 1851181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira RESULT_PICK_ATTACHMENT); 1852013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira } 1853013194caeba8848ba89a68c77843bed2bf7a38e5Mindy Pereira 1854ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira private void showCcBccViews() { 1855a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira mCcBccView.show(true, true, true); 1856ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira if (mCcBccButton != null) { 1857ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira mCcBccButton.setVisibility(View.GONE); 1858ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1859ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira } 1860ec8b0edb23c0e0b7f1a8ce9558a919be31169d45Mindy Pereira 1861326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 1862326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public boolean onNavigationItemSelected(int position, long itemId) { 1863a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira int initialComposeMode = mComposeMode; 1864326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (position == ComposeActivity.REPLY) { 1865326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY; 1866326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.REPLY_ALL) { 1867326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.REPLY_ALL; 1868326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } else if (position == ComposeActivity.FORWARD) { 1869326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mComposeMode = ComposeActivity.FORWARD; 1870326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1871a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira if (initialComposeMode != mComposeMode) { 1872154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira resetMessageForModeChange(); 18738eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira if (mRefMessage != null) { 18748eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira initFromRefMessage(mComposeMode, mAccount.name); 18758eca57a78ae01d9c8f55226734131aac1ff3c8aeMindy Pereira } 1876a26b54e3a858de409be3746e65591bb8a0d6ea9aMindy Pereira } 1877326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return true; 1878326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1879326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1880154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira private void resetMessageForModeChange() { 1881154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // When switching between reply, reply all, forward, 1882154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // follow the behavior of webview. 1883154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // The contents of the following fields are cleared 1884154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // so that they can be populated directly from the 1885154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // ref message: 1886154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Any recipient fields 1887154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) The subject 1888154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mTo.setText(""); 1889154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mCc.setText(""); 1890154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mBcc.setText(""); 1891154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any edits to the subject are replaced with the original subject. 1892154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mSubject.setText(""); 1893154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 1894154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // Any changes to the contents of the following fields are kept: 1895154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 1) Body 1896154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // 2) Attachments 1897154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira // If the user made changes to attachments, keep their changes. 1898154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira if (!mAttachmentsChanged) { 1899154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira mAttachmentsView.deleteAllAttachments(); 1900154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 1901154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira } 1902154386a287a9bfffb2eb3a4c05445f2774e1d4f0Mindy Pereira 1903326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private class ComposeModeAdapter extends ArrayAdapter<String> { 1904326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1905326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater mInflater; 1906326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1907326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public ComposeModeAdapter(Context context) { 1908326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira super(context, R.layout.compose_mode_item, R.id.mode, getResources() 1909326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira .getStringArray(R.array.compose_modes)); 1910326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1911326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1912326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira private LayoutInflater getInflater() { 1913326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (mInflater == null) { 1914326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mInflater = LayoutInflater.from(getContext()); 1915326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1916326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return mInflater; 1917326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1918326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 1919326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira @Override 1920326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 1921326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira if (convertView == null) { 1922326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira convertView = getInflater().inflate(R.layout.compose_mode_display_item, null); 1923326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1924326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira ((TextView) convertView.findViewById(R.id.mode)).setText(getItem(position)); 1925326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira return super.getView(position, convertView, parent); 1926326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 1927326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 192846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 192946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira @Override 193046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void onRespondInline(String text) { 193146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira appendToBody(text, false); 193246ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 193346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 193446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 193546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Append text to the body of the message. If there is no existing body 193646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * text, just sets the body to text. 193746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * 193846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 193946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 194046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 194146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void appendToBody(CharSequence text, boolean withSignature) { 1942eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira Editable bodyText = mBodyView.getEditableText(); 194346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira if (bodyText != null && bodyText.length() > 0) { 194446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira bodyText.append(text); 194546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } else { 194646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira setBody(text, withSignature); 194746ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 194846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 194946ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira 195046ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira /** 195146ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * Set the body of the message. 1952bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira * 195346ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param text 195446ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira * @param withSignature True to append a signature. 195546ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira */ 195646ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira public void setBody(CharSequence text, boolean withSignature) { 1957eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mBodyView.setText(text); 1958bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (withSignature) { 1959bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira appendSignature(); 1960bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1961bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1962bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1963bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private void appendSignature() { 1964b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira String newSignature = mCachedSettings != null ? mCachedSettings.signature : null; 1965433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira boolean hasFocus = mBodyView.hasFocus(); 1966b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.equals(newSignature, mSignature)) { 1967b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mSignature = newSignature; 1968b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira if (!TextUtils.isEmpty(mSignature) 1969b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira && getSignatureStartPosition(mSignature, 1970b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.getText().toString()) < 0) { 1971b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira // Appending a signature does not count as changing text. 1972b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.removeTextChangedListener(this); 1973b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.append(convertToPrintableSignature(mSignature)); 1974b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira mBodyView.addTextChangedListener(this); 1975b13917c3d753c6674db2a226668a7f3048ddc4b5Mindy Pereira } 1976433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira if (hasFocus) { 1977433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira focusBody(); 1978433b198e1a9385d1ca1284db0a168734768e0455Mindy Pereira } 1979bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1980bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1981bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira 1982bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira private String convertToPrintableSignature(String signature) { 1983bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira String signatureResource = getResources().getString(R.string.signature); 1984bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira if (signature == null) { 1985bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira signature = ""; 1986bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira } 1987bdf7a40583381ae26d11dcd0fca40bca230f96f3Mindy Pereira return String.format(signatureResource, signature); 198846ce0b13c33d1ade0e4537e780b41fea5e2a6be9Mindy Pereira } 19891a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira 19905a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira @Override 19915a85e2b7485a5c407c581219fe1b44417f050529Mindy Pereira public void onAccountChanged() { 199292551d057965689f1952faeb06763f0762bc717fMindy Pereira mReplyFromAccount = mFromSpinner.getCurrentAccount(); 199392551d057965689f1952faeb06763f0762bc717fMindy Pereira if (!mAccount.equals(mReplyFromAccount.account)) { 1994b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook setAccount(mReplyFromAccount.account); 1995b1f573c59ec20f9149443e1e0cc8b64ff3a07feaPaul Westbrook 1996181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // TODO: handle discarding attachments when switching accounts. 1997181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // Only enable save for this draft if there is any other content 1998181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira // in the message. 1999181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira if (!isBlank()) { 2000181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira enableSave(true); 2001181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira } 2002181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira mReplyFromChanged = true; 2003181df7851bd1eba4b6a3255073a8b731de23ae8fMindy Pereira initRecipients(); 200482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 20051a95a57f39da84cd7daf4e2161e50e518df51f13Mindy Pereira } 200682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 200782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSave(boolean enabled) { 200882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSave != null) { 200982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSave.setEnabled(enabled); 201082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 201182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 201282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 201382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void enableSend(boolean enabled) { 201482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mSend != null) { 201582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mSend.setEnabled(enabled); 201682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 201782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 201882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 201982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 202082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Handles button clicks from any error dialogs dealing with sending 202182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * a message. 202282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 202382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira @Override 202482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira public void onClick(DialogInterface dialog, int which) { 202582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira switch (which) { 202682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_POSITIVE: { 202782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira doDiscardWithoutConfirmation(true /* show toast */ ); 202882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 202982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 203082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira case DialogInterface.BUTTON_NEGATIVE: { 203182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // If the user cancels the send, re-enable the send button. 203282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira enableSend(true); 203382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira break; 203482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 203582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 203682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 203782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 203882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2039efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira private void doDiscard() { 2040efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira new AlertDialog.Builder(this).setMessage(R.string.confirm_discard_text) 2041efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setPositiveButton(R.string.ok, this) 2042efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .setNegativeButton(R.string.cancel, null) 2043efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira .create().show(); 2044efe3d25aa19da172fd5c3ec39539cdd91f29e927Mindy Pereira } 204582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira /** 204682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * Effectively discard the current message. 204782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * 204882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * This method is either invoked from the menu or from the dialog 204982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * once the user has confirmed that they want to discard the message. 205082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira * @param showToast show "Message discarded" toast if true 205182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira */ 205282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira private void doDiscardWithoutConfirmation(boolean showToast) { 20537ed1c1122c5677344a1ce176be2c03972fed26f5Mindy Pereira synchronized (mDraftLock) { 205482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (mDraftId != UIProvider.INVALID_MESSAGE_ID) { 205582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira ContentValues values = new ContentValues(); 2056b7050e62aab7133dea300d7fb3266311da99ec80Paul Westbrook values.put(BaseColumns._ID, mDraftId); 2057cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira if (mAccount.expungeMessageUri != null) { 2058cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira getContentResolver().update(mAccount.expungeMessageUri, values, null, null); 2059cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } else { 2060cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira // TODO(mindyp): call delete on this conversation instead. 2061cfb7f33ff8ef9dc60b9143af32de64c7a3d71f36Mindy Pereira } 206282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This is not strictly necessary (since we should not try to 206382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // save the draft after calling this) but it ensures that if we 206482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // do save again for some reason we make a new draft rather than 206582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // trying to resave an expunged draft. 206682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira mDraftId = UIProvider.INVALID_MESSAGE_ID; 206782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 206882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 206982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 207082cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira if (showToast) { 207182cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // Display a toast to let the user know 207282cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira Toast.makeText(this, R.string.message_discarded, Toast.LENGTH_SHORT).show(); 207382cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 207482cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 207582cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira // This prevents the draft from being saved in onPause(). 207682cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira discardChanges(); 207782cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira finish(); 207882cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira } 207982cc5665cb18801022cd60cd52abcd16a50debdcMindy Pereira 2080eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeeded() { 2081eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 2082eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 2083eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 2084eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 2085eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 2086eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2087eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2088eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 2089eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSave(!mAddingAttachment /* show toast */, true /* reset IME */); 2090eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2091eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2092eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2093eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira private void saveIfNeededOnOrientationChanged() { 2094eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (mAccount == null) { 2095eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // We have not chosen an account yet so there's no way that we can save. This is ok, 2096eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // though, since we are saving our state before AccountsActivity is activated. Thus, the 2097eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // user has not interacted with us yet and there is no real state to save. 2098eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return; 2099eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2100eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2101eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (shouldSave()) { 2102eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira doSaveOrientationChanged(!mAddingAttachment /* show toast */, true /* reset IME */); 2103eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2104eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2105eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2106eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira /** 2107eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira * Save a draft if a draft already exists or the message is not empty. 2108eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira */ 2109eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void doSaveOrientationChanged(boolean showToast, boolean resetIME) { 2110eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira saveOnOrientationChanged(); 2111eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira if (resetIME) { 2112eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira // Clear the IME composing suggestions from the body. 2113eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira BaseInputConnection.removeComposingSpans(mBodyView.getEditableText()); 2114eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2115eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2116eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2117eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira protected boolean saveOnOrientationChanged() { 2118eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira return sendOrSaveWithSanityChecks(true, false, true); 2119eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 2120eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira 2121eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira @Override 2122eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira public void onAttachmentDeleted() { 2123eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira mAttachmentsChanged = true; 2124eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira updateSaveUi(); 2125eaea9f16b2b61eed6b62fe9a5c567bfbe0d75d80Mindy Pereira } 212675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 212775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 212875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira /** 212975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira * This is called any time one of our text fields changes. 213075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira */ 213175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 213275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mTextChanged = true; 213375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira updateSaveUi(); 213475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 213575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 213675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 213775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 213875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 213975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 214075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 214175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 214275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 214375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 214475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 214575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 214675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // There is a big difference between the text associated with an address changing 214775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // to add the display name or to format properly and a recipient being added or deleted. 214875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Make sure we only notify of changes when a recipient has been added or deleted. 214975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private class RecipientTextWatcher implements TextWatcher { 215075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private HashMap<String, Integer> mContent = new HashMap<String, Integer>(); 215175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 215275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private RecipientEditTextView mView; 215375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 215475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private TextWatcher mListener; 215575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 215675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public RecipientTextWatcher(RecipientEditTextView view, TextWatcher listener) { 215775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mView = view; 215875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener = listener; 215975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 216075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 216175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 216275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void afterTextChanged(Editable s) { 216375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (hasChanged()) { 216475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mListener.afterTextChanged(s); 216575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 216675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 216775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 216875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private boolean hasChanged() { 216975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] currRecips = tokenizeRecips(getAddressesFromList(mView)); 217075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalCount = currRecips.length; 217175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int totalPrevCount = 0; 217275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (Entry<String, Integer> entry : mContent.entrySet()) { 217375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira totalPrevCount += entry.getValue(); 217475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 217575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (totalCount != totalPrevCount) { 217675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 217775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 217875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 217975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : currRecips) { 218075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 218175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 218275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 218375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira int count = mContent.get(recip) - 1; 218475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (count < 0) { 218575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return true; 218675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 218775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, count); 218875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 218975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 219075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 219175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return false; 219275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 219375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 219475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira private String[] tokenizeRecips(String[] recips) { 219575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Tokenize them all and put them in the list. 219675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recipAddresses = new String[recips.length]; 219775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (int i = 0; i < recips.length; i++) { 219875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira recipAddresses[i] = Rfc822Tokenizer.tokenize(recips[i])[0].getAddress(); 219975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 220075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira return recipAddresses; 220175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 220275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 220375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 220475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void beforeTextChanged(CharSequence s, int start, int count, int after) { 220575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira String[] recips = tokenizeRecips(getAddressesFromList(mView)); 220675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira for (String recip : recips) { 220775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira if (!mContent.containsKey(recip)) { 220875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, 1); 220975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } else { 221075f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira mContent.put(recip, (mContent.get(recip)) + 1); 221175f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 221275f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 221375f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 221475f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira 221575f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira @Override 221675f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira public void onTextChanged(CharSequence s, int start, int before, int count) { 221775f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira // Do nothing. 221875f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 221975f66634dd18cc8d8e6f40c4573c0edf0a0343efMindy Pereira } 22208e9305ec0bbe23cec01eb34a2aee76c55199a10aMindy Pereira}