diff --git a/emailcommon/src/com/android/emailcommon/service/AccountServiceProxy.java b/emailcommon/src/com/android/emailcommon/service/AccountServiceProxy.java index f4eb93009..d65473894 100644 --- a/emailcommon/src/com/android/emailcommon/service/AccountServiceProxy.java +++ b/emailcommon/src/com/android/emailcommon/service/AccountServiceProxy.java @@ -45,11 +45,11 @@ public class AccountServiceProxy extends ServiceProxy implements IAccountService } @Override - public void notifyLoginFailed(final long accountId) { + public void notifyLoginFailed(final long accountId, final String reason) { setTask(new ProxyTask() { @Override public void run() throws RemoteException { - mService.notifyLoginFailed(accountId); + mService.notifyLoginFailed(accountId, reason); } }, "notifyLoginFailed"); } diff --git a/emailcommon/src/com/android/emailcommon/service/IAccountService.aidl b/emailcommon/src/com/android/emailcommon/service/IAccountService.aidl index a29baf58c..d456862b0 100644 --- a/emailcommon/src/com/android/emailcommon/service/IAccountService.aidl +++ b/emailcommon/src/com/android/emailcommon/service/IAccountService.aidl @@ -19,7 +19,7 @@ package com.android.emailcommon.service; import android.os.Bundle; interface IAccountService { - oneway void notifyLoginFailed(long accountId); + oneway void notifyLoginFailed(long accountId, String reason); oneway void notifyLoginSucceeded(long accountId); void reconcileAccounts(String protocol, String accountManagerType); diff --git a/emailsync/src/com/android/emailsync/AbstractSyncService.java b/emailsync/src/com/android/emailsync/AbstractSyncService.java index 7cbf13ac5..c9b151a4f 100644 --- a/emailsync/src/com/android/emailsync/AbstractSyncService.java +++ b/emailsync/src/com/android/emailsync/AbstractSyncService.java @@ -59,6 +59,7 @@ public abstract class AbstractSyncService implements Runnable { public Mailbox mMailbox; protected long mMailboxId; protected int mExitStatus = EXIT_EXCEPTION; + protected String mExitReason; protected String mMailboxName; public Account mAccount; public Context mContext; diff --git a/emailsync/src/com/android/emailsync/SyncManager.java b/emailsync/src/com/android/emailsync/SyncManager.java index 9360b070c..d81abee60 100644 --- a/emailsync/src/com/android/emailsync/SyncManager.java +++ b/emailsync/src/com/android/emailsync/SyncManager.java @@ -2209,7 +2209,7 @@ public abstract class SyncManager extends Service implements Runnable { break; // These errors are not retried automatically case AbstractSyncService.EXIT_LOGIN_FAILURE: - new AccountServiceProxy(ssm).notifyLoginFailed(m.mAccountKey); + new AccountServiceProxy(ssm).notifyLoginFailed(m.mAccountKey, svc.mExitReason); lastResult = EmailContent.LAST_SYNC_RESULT_AUTH_ERROR; break; case AbstractSyncService.EXIT_SECURITY_FAILURE: diff --git a/imap2/src/com/android/imap2/Imap2SyncService.java b/imap2/src/com/android/imap2/Imap2SyncService.java index 5e84ebe76..28135916a 100644 --- a/imap2/src/com/android/imap2/Imap2SyncService.java +++ b/imap2/src/com/android/imap2/Imap2SyncService.java @@ -101,6 +101,7 @@ public class Imap2SyncService extends AbstractSyncService { private static final SimpleDateFormat GMAIL_INTERNALDATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yy HH:mm:ss z"); private static final String IMAP_ERR = "ERR"; + private static final String IMAP_NO = "NO"; private static final SimpleDateFormat IMAP_DATE_FORMAT = new SimpleDateFormat("dd-MMM-yyyy"); @@ -1573,6 +1574,7 @@ public class Imap2SyncService extends AbstractSyncService { public static class Connection { Socket socket; int status; + String reason; ImapInputStream reader; BufferedWriter writer; @@ -1649,7 +1651,13 @@ public class Imap2SyncService extends AbstractSyncService { tag = writeCommand(writer, "login " + hostAuth.mLogin + ' ' + hostAuth.mPassword); - if (!readResponse(reader, tag).equals(IMAP_OK)) { + if (!IMAP_OK.equals(readResponse(reader, tag))) { + if (IMAP_NO.equals(mImapResult)) { + int alertPos = mImapErrorLine.indexOf("[ALERT]"); + if (alertPos > 0) { + conn.reason = mImapErrorLine.substring(alertPos + 7); + } + } conn.status = EXIT_LOGIN_FAILURE; } else { conn.socket = socket; @@ -1960,6 +1968,7 @@ public class Imap2SyncService extends AbstractSyncService { Connection conn = connectAndLogin(hostAuth, "main"); if (conn.status != EXIT_DONE) { mExitStatus = conn.status; + mExitReason = conn.reason; return; } setConnection(conn); diff --git a/res/values/strings.xml b/res/values/strings.xml index 90317fdf7..a6f3b543e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -911,11 +911,16 @@ as %s. Couldn\'t sign in - The username or password for %s is incorrect. Do you want to update them now? + + + Your login to %s failed; the server said: %s + Do you want to update your username and/or password? Default account diff --git a/src/com/android/email/NotificationController.java b/src/com/android/email/NotificationController.java index ca87c65fd..bde5db9e1 100644 --- a/src/com/android/email/NotificationController.java +++ b/src/com/android/email/NotificationController.java @@ -747,6 +747,10 @@ public class NotificationController { * NOTE: DO NOT CALL THIS METHOD FROM THE UI THREAD (DATABASE ACCESS) */ public void showLoginFailedNotification(long accountId) { + showLoginFailedNotification(accountId, null); + } + + public void showLoginFailedNotification(long accountId, String reason) { final Account account = Account.restoreAccountWithId(mContext, accountId); if (account == null) return; final Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, account.mId, @@ -757,7 +761,7 @@ public class NotificationController { mContext.getString(R.string.login_failed_title), account.getDisplayName(), AccountSettings.createAccountSettingsIntent(mContext, accountId, - account.mDisplayName), + account.mDisplayName, reason), getLoginFailedNotificationId(accountId)); } @@ -841,7 +845,8 @@ public class NotificationController { * account settings screen where he can view the list of enforced policies */ public void showSecurityChangedNotification(Account account) { - Intent intent = AccountSettings.createAccountSettingsIntent(mContext, account.mId, null); + Intent intent = + AccountSettings.createAccountSettingsIntent(mContext, account.mId, null, null); String accountName = account.getDisplayName(); String ticker = mContext.getString(R.string.security_changed_ticker_fmt, accountName); @@ -855,7 +860,8 @@ public class NotificationController { * account settings screen where he can view the list of unsupported policies */ public void showSecurityUnsupportedNotification(Account account) { - Intent intent = AccountSettings.createAccountSettingsIntent(mContext, account.mId, null); + Intent intent = + AccountSettings.createAccountSettingsIntent(mContext, account.mId, null, null); String accountName = account.getDisplayName(); String ticker = mContext.getString(R.string.security_unsupported_ticker_fmt, accountName); diff --git a/src/com/android/email/activity/setup/AccountSettings.java b/src/com/android/email/activity/setup/AccountSettings.java index 23eb17fa9..b64b95ded 100644 --- a/src/com/android/email/activity/setup/AccountSettings.java +++ b/src/com/android/email/activity/setup/AccountSettings.java @@ -76,6 +76,8 @@ public class AccountSettings extends PreferenceActivity { // Intent extras for our internal activity launch private static final String EXTRA_ENABLE_DEBUG = "AccountSettings.enable_debug"; private static final String EXTRA_LOGIN_WARNING_FOR_ACCOUNT = "AccountSettings.for_account"; + private static final String EXTRA_LOGIN_WARNING_REASON_FOR_ACCOUNT = + "AccountSettings.for_account_reason"; private static final String EXTRA_TITLE = "AccountSettings.title"; public static final String EXTRA_NO_ACCOUNTS = "AccountSettings.no_account"; @@ -127,7 +129,8 @@ public class AccountSettings extends PreferenceActivity { * Display (and edit) settings for a specific account, or -1 for any/all accounts */ public static void actionSettings(Activity fromActivity, long accountId) { - fromActivity.startActivity(createAccountSettingsIntent(fromActivity, accountId, null)); + fromActivity.startActivity( + createAccountSettingsIntent(fromActivity, accountId, null, null)); } /** @@ -136,13 +139,16 @@ public class AccountSettings extends PreferenceActivity { * displayed as well. */ public static Intent createAccountSettingsIntent(Context context, long accountId, - String loginWarningAccountName) { + String loginWarningAccountName, String loginWarningReason) { final Uri.Builder b = IntentUtilities.createActivityIntentUrlBuilder("settings"); IntentUtilities.setAccountId(b, accountId); Intent i = new Intent(Intent.ACTION_EDIT, b.build()); if (loginWarningAccountName != null) { i.putExtra(EXTRA_LOGIN_WARNING_FOR_ACCOUNT, loginWarningAccountName); } + if (loginWarningReason != null) { + i.putExtra(EXTRA_LOGIN_WARNING_REASON_FOR_ACCOUNT, loginWarningReason); + } return i; } @@ -182,9 +188,12 @@ public class AccountSettings extends PreferenceActivity { // Otherwise, we're called from within the Email app and look for our extras mRequestedAccountId = IntentUtilities.getAccountIdFromIntent(i); String loginWarningAccount = i.getStringExtra(EXTRA_LOGIN_WARNING_FOR_ACCOUNT); + String loginWarningReason = + i.getStringExtra(EXTRA_LOGIN_WARNING_REASON_FOR_ACCOUNT); if (loginWarningAccount != null) { // Show dialog (first time only - don't re-show on a rotation) - LoginWarningDialog dialog = LoginWarningDialog.newInstance(loginWarningAccount); + LoginWarningDialog dialog = + LoginWarningDialog.newInstance(loginWarningAccount, loginWarningReason); dialog.show(getFragmentManager(), "loginwarning"); } } @@ -809,15 +818,17 @@ public class AccountSettings extends PreferenceActivity { public static class LoginWarningDialog extends DialogFragment implements DialogInterface.OnClickListener { private static final String BUNDLE_KEY_ACCOUNT_NAME = "account_name"; + private String mReason; /** * Create a new dialog. */ - public static LoginWarningDialog newInstance(String accountName) { + public static LoginWarningDialog newInstance(String accountName, String reason) { final LoginWarningDialog dialog = new LoginWarningDialog(); Bundle b = new Bundle(); b.putString(BUNDLE_KEY_ACCOUNT_NAME, accountName); dialog.setArguments(b); + dialog.mReason = reason; return dialog; } @@ -830,8 +841,13 @@ public class AccountSettings extends PreferenceActivity { final AlertDialog.Builder b = new AlertDialog.Builder(context); b.setTitle(R.string.account_settings_login_dialog_title); b.setIconAttribute(android.R.attr.alertDialogIcon); - b.setMessage(res.getString(R.string.account_settings_login_dialog_content_fmt, - accountName)); + if (mReason != null) { + b.setMessage(res.getString(R.string.account_settings_login_dialog_reason_fmt, + accountName, mReason)); + } else { + b.setMessage(res.getString(R.string.account_settings_login_dialog_content_fmt, + accountName)); + } b.setPositiveButton(R.string.okay_action, this); b.setNegativeButton(R.string.cancel_action, this); return b.create(); diff --git a/src/com/android/email/service/AccountService.java b/src/com/android/email/service/AccountService.java index 56f432a7d..b79842fa1 100644 --- a/src/com/android/email/service/AccountService.java +++ b/src/com/android/email/service/AccountService.java @@ -47,8 +47,9 @@ public class AccountService extends Service { private final IAccountService.Stub mBinder = new IAccountService.Stub() { @Override - public void notifyLoginFailed(long accountId) { - NotificationController.getInstance(mContext).showLoginFailedNotification(accountId); + public void notifyLoginFailed(long accountId, String reason) { + NotificationController nc = NotificationController.getInstance(mContext); + nc.showLoginFailedNotification(accountId, reason); } @Override