diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dcf228f94..bafc088cf 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -266,10 +266,8 @@
android:exported="true"
>
-
-
+
+
@@ -285,6 +283,19 @@
+
+
+
+
+
+
+
+
+
{
+ private final Context mContext;
+
+ private LoadAccountIncomingSettingsAsyncTask(Context context) {
+ mContext = context;
+ }
+
+ protected Account doInBackground(Long... params) {
+ return Account.restoreAccountWithId(mContext, params[0]);
+ }
+
+ protected void onPostExecute(Account result) {
+ // create an Intent to view a new activity
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // we are navigating explicitly to the AccountSettings activity
+ intent.setClass(mContext, AccountSettings.class);
+
+ // place the account in the intent as an extra
+ intent.putExtra(AccountSettings.EXTRA_ACCOUNT, result);
+
+ // these extras show the "incoming fragment" in the AccountSettings activity by default
+ intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,
+ AccountSetupIncomingFragment.class.getCanonicalName());
+ intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS,
+ AccountSetupIncomingFragment.getArgs(true));
+ intent.putExtra(PreferenceActivity.EXTRA_NO_HEADERS, true);
+
+ mContext.startActivity(intent);
+
+ finish();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/email/mail/store/ImapConnection.java b/src/com/android/email/mail/store/ImapConnection.java
index 88a8eaa91..2e9019edd 100644
--- a/src/com/android/email/mail/store/ImapConnection.java
+++ b/src/com/android/email/mail/store/ImapConnection.java
@@ -97,9 +97,10 @@ class ImapConnection {
* Generates and returns the phrase to be used for authentication. This will be a LOGIN with
* username and password, or an OAUTH authentication string, with username and access token.
* Currently, these are the only two auth mechanisms supported.
- * @return
+ *
* @throws IOException
* @throws AuthenticationFailedException
+ * @return the login command string to sent to the IMAP server
*/
String getLoginPhrase() throws MessagingException, IOException {
// build the LOGIN string once (instead of over-and-over again.)
@@ -197,7 +198,7 @@ class ImapConnection {
/**
* Closes the connection and releases all resources. This connection can not be used again
- * until {@link #setStore(ImapStore, String, String)} is called.
+ * until {@link #setStore(ImapStore)} is called.
*/
void close() {
if (mTransport != null) {
@@ -255,7 +256,7 @@ class ImapConnection {
}
boolean isTransportOpenForTest() {
- return mTransport != null ? mTransport.isOpen() : false;
+ return mTransport != null && mTransport.isOpen();
}
ImapResponse readResponse() throws IOException, MessagingException {
@@ -315,8 +316,7 @@ class ImapConnection {
return tag;
}
- List executeSimpleCommand(String command) throws IOException,
- MessagingException {
+ List executeSimpleCommand(String command) throws IOException, MessagingException {
return executeSimpleCommand(command, false);
}
@@ -328,17 +328,25 @@ class ImapConnection {
* @throws MessagingException
*/
List getCommandResponses() throws IOException, MessagingException {
- ArrayList responses = new ArrayList();
+ final List responses = new ArrayList();
ImapResponse response;
do {
response = mParser.readResponse();
responses.add(response);
} while (!response.isTagged());
+
if (!response.isOk()) {
final String toString = response.toString();
final String alert = response.getAlertTextOrEmpty().getString();
+ final String responseCode = response.getResponseCodeOrEmpty().getString();
destroyResponses();
- throw new ImapException(toString, alert);
+
+ // if the response code indicates an error occurred within the server, indicate that
+ if (ImapConstants.UNAVAILABLE.equals(responseCode)) {
+ throw new MessagingException(MessagingException.SERVER_ERROR, alert);
+ }
+
+ throw new ImapException(toString, alert, responseCode);
}
return responses;
}
@@ -476,8 +484,7 @@ class ImapConnection {
/**
* Logs into the IMAP server
*/
- private void doLogin()
- throws IOException, MessagingException, AuthenticationFailedException {
+ private void doLogin() throws IOException, MessagingException, AuthenticationFailedException {
try {
if (mImapStore.getUseOAuth()) {
// SASL authentication can take multiple steps. Currently the only SASL
@@ -490,10 +497,17 @@ class ImapConnection {
if (MailActivityEmail.DEBUG) {
LogUtils.d(Logging.LOG_TAG, ie, "ImapException");
}
- throw new AuthenticationFailedException(ie.getAlertText(), ie);
- } catch (MessagingException me) {
- throw new AuthenticationFailedException(null, me);
+ final String code = ie.getResponseCode();
+ final String alertText = ie.getAlertText();
+
+ // if the response code indicates expired or bad credentials, throw a special exception
+ if (ImapConstants.AUTHENTICATIONFAILED.equals(code) ||
+ ImapConstants.EXPIRED.equals(code)) {
+ throw new AuthenticationFailedException(alertText, ie);
+ }
+
+ throw new MessagingException(alertText, ie);
}
}
@@ -542,8 +556,15 @@ class ImapConnection {
sendCommand("", true);
response = readResponse();
}
- return response;
+ // if the response code indicates an error occurred within the server, indicate that
+ final String responseCode = response.getResponseCodeOrEmpty().getString();
+ if (ImapConstants.UNAVAILABLE.equals(responseCode)) {
+ final String alert = response.getAlertTextOrEmpty().getString();
+ throw new MessagingException(MessagingException.SERVER_ERROR, alert);
+ }
+
+ return response;
}
/**
diff --git a/src/com/android/email/mail/store/ImapFolder.java b/src/com/android/email/mail/store/ImapFolder.java
index 4f9588b00..30857360c 100644
--- a/src/com/android/email/mail/store/ImapFolder.java
+++ b/src/com/android/email/mail/store/ImapFolder.java
@@ -59,10 +59,10 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
-import java.util.Locale;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Locale;
import java.util.TimeZone;
class ImapFolder extends Folder {
@@ -1236,7 +1236,7 @@ class ImapFolder extends Folder {
mConnection = null; // To prevent close() from returning the connection to the pool.
close(false);
}
- return new MessagingException("IO Error", ioe);
+ return new MessagingException(MessagingException.IOERROR, "IO Error", ioe);
}
@Override
diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java
index b14e58d34..82bb289b4 100644
--- a/src/com/android/email/mail/store/ImapStore.java
+++ b/src/com/android/email/mail/store/ImapStore.java
@@ -627,29 +627,26 @@ public class ImapStore extends Store {
static class ImapException extends MessagingException {
private static final long serialVersionUID = 1L;
- String mAlertText;
+ private final String mAlertText;
+ private final String mResponseCode;
- public ImapException(String message, String alertText, Throwable throwable) {
- super(message, throwable);
- mAlertText = alertText;
- }
-
- public ImapException(String message, String alertText) {
+ public ImapException(String message, String alertText, String responseCode) {
super(message);
mAlertText = alertText;
+ mResponseCode = responseCode;
}
public String getAlertText() {
return mAlertText;
}
- public void setAlertText(String alertText) {
- mAlertText = alertText;
+ public String getResponseCode() {
+ return mResponseCode;
}
}
public void closeConnections() {
- ImapConnection connection = null;
+ ImapConnection connection;
while ((connection = mConnectionPool.poll()) != null) {
connection.close();
}
diff --git a/src/com/android/email/mail/store/imap/ImapConstants.java b/src/com/android/email/mail/store/imap/ImapConstants.java
index 5a3290420..9f4d59290 100644
--- a/src/com/android/email/mail/store/imap/ImapConstants.java
+++ b/src/com/android/email/mail/store/imap/ImapConstants.java
@@ -96,4 +96,9 @@ public final class ImapConstants {
public static final String XOAUTH2 = "XOAUTH2";
public static final String APPENDUID = "APPENDUID";
public static final String NIL = "NIL";
+
+ /** response codes within IMAP responses */
+ public static final String EXPIRED = "EXPIRED";
+ public static final String AUTHENTICATIONFAILED = "AUTHENTICATIONFAILED";
+ public static final String UNAVAILABLE = "UNAVAILABLE";
}
diff --git a/src/com/android/email/provider/EmailProvider.java b/src/com/android/email/provider/EmailProvider.java
index e20e487d8..e4ab1a0fc 100644
--- a/src/com/android/email/provider/EmailProvider.java
+++ b/src/com/android/email/provider/EmailProvider.java
@@ -98,6 +98,7 @@ import com.android.emailcommon.service.EmailServiceStatus;
import com.android.emailcommon.service.IEmailService;
import com.android.emailcommon.service.SearchParams;
import com.android.emailcommon.utility.AttachmentUtilities;
+import com.android.emailcommon.utility.IntentUtilities;
import com.android.emailcommon.utility.Utility;
import com.android.ex.photo.provider.PhotoContract;
import com.android.mail.preferences.MailPrefs;
@@ -171,6 +172,9 @@ public class EmailProvider extends ContentProvider {
private static final String EMAIL_ATTACHMENT_MIME_TYPE =
"vnd.android.cursor.item/email-attachment";
+ /** The base of the URI that navigates to the settings page to alter email auth credentials */
+ private static Uri BASE_AUTH_URI;
+
/** Appended to the notification URI for delete operations */
private static final String NOTIFICATION_OP_DELETE = "delete";
/** Appended to the notification URI for insert operations */
@@ -1001,6 +1005,8 @@ public class EmailProvider extends ContentProvider {
UIPROVIDER_RECENT_FOLDERS_NOTIFIER =
Uri.parse("content://" + uiNotificationAuthority + "/uirecentfolders");
+ BASE_AUTH_URI = Uri.parse("auth://" + EmailContent.EMAIL_PACKAGE_NAME +
+ ".INCOMING_SETTINGS/incoming/");
// All accounts
sURIMatcher.addURI(EmailContent.AUTHORITY, "account", ACCOUNT);
@@ -3024,6 +3030,12 @@ public class EmailProvider extends ContentProvider {
.appendQueryParameter("account", account).build().toString();
}
+ private static String getExternalUriStringReathentication(long accountId) {
+ final Uri.Builder builder = BASE_AUTH_URI.buildUpon();
+ IntentUtilities.setAccountId(builder, accountId);
+ return builder.build().toString();
+ }
+
private static String getBits(int bitField) {
StringBuilder sb = new StringBuilder(" ");
for (int i = 0; i < 32; i++, bitField >>= 1) {
@@ -3125,6 +3137,10 @@ public class EmailProvider extends ContentProvider {
values.put(UIProvider.AccountColumns.COMPOSE_URI,
getExternalUriStringEmail2("compose", id));
}
+ if (projectionColumns.contains(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI)) {
+ values.put(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI,
+ getExternalUriStringReathentication(accountId));
+ }
if (projectionColumns.contains(UIProvider.AccountColumns.MIME_TYPE)) {
values.put(UIProvider.AccountColumns.MIME_TYPE, EMAIL_APP_MIME_TYPE);
}
diff --git a/src/com/android/email/service/PopImapSyncAdapterService.java b/src/com/android/email/service/PopImapSyncAdapterService.java
index 4099be5c2..4b62860e0 100644
--- a/src/com/android/email/service/PopImapSyncAdapterService.java
+++ b/src/com/android/email/service/PopImapSyncAdapterService.java
@@ -144,24 +144,27 @@ public class PopImapSyncAdapterService extends Service {
UIProvider.LastSyncResult.SUCCESS);
}
} catch (MessagingException e) {
- int cause = e.getExceptionType();
- // XXX It's no good to put the MessagingException.cause here, that's not the
- // same set of values that we use in EmailServiceStatus.
- switch(cause) {
+ final int type = e.getExceptionType();
+ // type must be translated into the domain of values used by EmailServiceStatus
+ switch(type) {
case MessagingException.IOERROR:
- EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, cause, 0,
+ EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, type, 0,
UIProvider.LastSyncResult.CONNECTION_ERROR);
syncResult.stats.numIoExceptions++;
break;
case MessagingException.AUTHENTICATION_FAILED:
- EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, cause, 0,
+ EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, type, 0,
UIProvider.LastSyncResult.AUTH_ERROR);
syncResult.stats.numAuthExceptions++;
break;
+ case MessagingException.SERVER_ERROR:
+ EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, type, 0,
+ UIProvider.LastSyncResult.SERVER_ERROR);
+ break;
default:
- EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, cause, 0,
- UIProvider.LastSyncResult.INTERNAL_ERROR);
+ EmailServiceStatus.syncMailboxStatus(resolver, extras, mailboxId, type, 0,
+ UIProvider.LastSyncResult.INTERNAL_ERROR);
}
}
} finally {