Handle ALERT response to login command
* Allow AccountService loginFailed API to take a reason string * Present the reason string in the dialog shown from the login failure notification * Handle ALERTs in IMAP login responses (for example, some servers will occasionally require web login and we need to inform them, rather than simply saying the password is wrong) * This fixes a longstanding bug in our Imap1 implementation Change-Id: I8b270cd5d4746559b6c8a78bce02f0e7c525bdea
This commit is contained in:
parent
ae57810e1e
commit
dba0b20d95
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -911,11 +911,16 @@ as <xliff:g id="filename">%s</xliff:g>.</string>
|
|||
<!-- On AccountSettingsXL, dialog title if you were brought here due to a login failure.
|
||||
[CHAR_LIMIT=40] -->
|
||||
<string name="account_settings_login_dialog_title">Couldn\'t sign in</string>
|
||||
<!-- On AccountSettingsXL, dialog content if you were brought here due to a login failure.
|
||||
<!-- Dialog content if you were brought here due to a login failure.
|
||||
[CHAR_LIMIT=none] -->
|
||||
<string name="account_settings_login_dialog_content_fmt">
|
||||
The username or password for <xliff:g id="account">%s</xliff:g> is incorrect.
|
||||
Do you want to update them now?</string>
|
||||
<!-- Dialog content if you were brought here due to a login failure, and the server provided a reason
|
||||
[CHAR_LIMIT=none] -->
|
||||
<string name="account_settings_login_dialog_reason_fmt">
|
||||
Your login to <xliff:g id="account">%s</xliff:g> failed; the server said: <xliff:g id="reason">%s</xliff:g>
|
||||
Do you want to update your username and/or password?</string>
|
||||
|
||||
<!-- On Settings screen, setting option name -->
|
||||
<string name="account_settings_default_label">Default account</string>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue