Use notifications for login failures
* For now, clicking on the notification takes the user to the
Welcome activity, as we don't have final flows for the new
account setup UI
* Need comment on strings; the problem is that notification
text must be rather short if we're to use the standard
notification display. It looks like newer UI will allow
3 lines instead of 2, however.
* Tested w/ IMAP, POP3, EAS, and SMTP
Bug: 2322253
Change-Id: I7ed6fa5599179870cbcdb14af062e956eff37ec5
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f8cfcd1..265e254 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -378,11 +378,15 @@
messages moved to <xliff:g id="mailbox_name" example="Inbox" >%2$s</xliff:g></item>
</plurals>
<!-- Notification ticker when a forwarded attachment couldn't be sent [CHAR LIMIT=none] -->
- <string name="forward_download_failed_ticker">"An attachment couldn't be forwarded"</string>
+ <string name="forward_download_failed_ticker">Could not forward one or more attachments</string>
<!-- Notification text when a forwarded attachment couldn't be sent -->
- <string name="forward_download_failed_notification">"The attachment "<xliff:g id="filename">%s
- </xliff:g>" couldn't be sent with your outgoing mail because it couldn't be downloaded."
- </string>
+ <string name="forward_download_failed_notification">Could not forward <xliff:g id="filename">
+ %s</xliff:g></string>
+ <!-- Notification ticker when email account authentication fails [CHAR LIMIT=20] -->
+ <string name="login_failed_ticker"><xliff:g id="account_name">%s
+ </xliff:g> sign-in failed</string>
+ <!-- Notification text when email account authentication fails [CHAR LIMIT=75]-->
+ <string name="login_failed_notification">Touch to change account settings</string>
<!-- Size unit for bytes for attachments [CHAR LIMIT=10] -->
<plurals name="message_view_attachment_bytes">
diff --git a/src/com/android/exchange/ExchangeService.java b/src/com/android/exchange/ExchangeService.java
index 7b87b75..6f103b0 100644
--- a/src/com/android/exchange/ExchangeService.java
+++ b/src/com/android/exchange/ExchangeService.java
@@ -19,6 +19,7 @@
import com.android.email.AccountBackupRestore;
import com.android.email.Email;
+import com.android.email.NotificationController;
import com.android.email.Utility;
import com.android.email.mail.transport.SSLUtils;
import com.android.email.provider.EmailContent;
@@ -975,14 +976,17 @@
* is null, mailboxes from all accounts with the specified hold will be released
* @param reason the reason for the SyncError (AbstractSyncService.EXIT_XXX)
* @param account an Account whose mailboxes should be released (or all if null)
+ * @return whether or not any mailboxes were released
*/
- /*package*/ void releaseSyncHolds(Context context, int reason, Account account) {
- releaseSyncHoldsImpl(context, reason, account);
+ /*package*/ boolean releaseSyncHolds(Context context, int reason, Account account) {
+ boolean holdWasReleased = releaseSyncHoldsImpl(context, reason, account);
kick("security release");
+ return holdWasReleased;
}
- private void releaseSyncHoldsImpl(Context context, int reason, Account account) {
+ private boolean releaseSyncHoldsImpl(Context context, int reason, Account account) {
synchronized(sSyncLock) {
+ boolean holdWasReleased = false;
ArrayList<Long> releaseList = new ArrayList<Long>();
for (long mailboxId: mSyncErrorMap.keySet()) {
if (account != null) {
@@ -1000,7 +1004,9 @@
}
for (long mailboxId: releaseList) {
mSyncErrorMap.remove(mailboxId);
+ holdWasReleased = true;
}
+ return holdWasReleased;
}
}
@@ -2376,6 +2382,20 @@
SyncError syncError = errorMap.get(mailboxId);
exchangeService.releaseMailbox(mailboxId);
int exitStatus = svc.mExitStatus;
+ Mailbox m = Mailbox.restoreMailboxWithId(exchangeService, mailboxId);
+ if (m == null) return;
+
+ if (exitStatus != AbstractSyncService.EXIT_LOGIN_FAILURE) {
+ long accountId = m.mAccountKey;
+ Account account = Account.restoreAccountWithId(exchangeService, accountId);
+ if (account == null) return;
+ if (exchangeService.releaseSyncHolds(exchangeService,
+ AbstractSyncService.EXIT_LOGIN_FAILURE, account)) {
+ NotificationController.getInstance(exchangeService)
+ .cancelLoginFailedNotification(accountId);
+ }
+ }
+
switch (exitStatus) {
case AbstractSyncService.EXIT_DONE:
if (svc.hasPendingRequests()) {
@@ -2389,8 +2409,6 @@
break;
// I/O errors get retried at increasing intervals
case AbstractSyncService.EXIT_IO_ERROR:
- Mailbox m = Mailbox.restoreMailboxWithId(exchangeService, mailboxId);
- if (m == null) return;
if (syncError != null) {
syncError.escalate();
log(m.mDisplayName + " held for " + syncError.holdDelay + "ms");
@@ -2400,8 +2418,11 @@
}
break;
// These errors are not retried automatically
- case AbstractSyncService.EXIT_SECURITY_FAILURE:
case AbstractSyncService.EXIT_LOGIN_FAILURE:
+ NotificationController.getInstance(exchangeService)
+ .showLoginFailedNotification(m.mAccountKey);
+ // Fall through
+ case AbstractSyncService.EXIT_SECURITY_FAILURE:
case AbstractSyncService.EXIT_EXCEPTION:
errorMap.put(mailboxId, exchangeService.new SyncError(exitStatus, true));
break;
diff --git a/tests/src/com/android/exchange/ExchangeServiceAccountTests.java b/tests/src/com/android/exchange/ExchangeServiceAccountTests.java
index 425e9c4..9b92726 100644
--- a/tests/src/com/android/exchange/ExchangeServiceAccountTests.java
+++ b/tests/src/com/android/exchange/ExchangeServiceAccountTests.java
@@ -73,7 +73,8 @@
// We should have 4
assertEquals(4, errorMap.keySet().size());
// Release the holds on acct2 (there are two of them)
- exchangeService.releaseSyncHolds(context, AbstractSyncService.EXIT_SECURITY_FAILURE, acct2);
+ assertTrue(exchangeService.releaseSyncHolds(context,
+ AbstractSyncService.EXIT_SECURITY_FAILURE, acct2));
// There should be two left
assertEquals(2, errorMap.keySet().size());
// And these are the two...
@@ -86,19 +87,22 @@
// We should have 4 again
assertEquals(4, errorMap.keySet().size());
// Release all of the security holds
- exchangeService.releaseSyncHolds(context, AbstractSyncService.EXIT_SECURITY_FAILURE, null);
+ assertTrue(exchangeService.releaseSyncHolds(context,
+ AbstractSyncService.EXIT_SECURITY_FAILURE, null));
// There should be one left
assertEquals(1, errorMap.keySet().size());
// And this is the one
assertNotNull(errorMap.get(box2.mId));
// Release the i/o holds on account 2 (there aren't any)
- exchangeService.releaseSyncHolds(context, AbstractSyncService.EXIT_IO_ERROR, acct2);
+ assertFalse(exchangeService.releaseSyncHolds(context,
+ AbstractSyncService.EXIT_IO_ERROR, acct2));
// There should still be one left
assertEquals(1, errorMap.keySet().size());
// Release the i/o holds on account 1 (there's one)
- exchangeService.releaseSyncHolds(context, AbstractSyncService.EXIT_IO_ERROR, acct1);
+ assertTrue(exchangeService.releaseSyncHolds(context,
+ AbstractSyncService.EXIT_IO_ERROR, acct1));
// There should still be one left
assertEquals(0, errorMap.keySet().size());
}