Better fix for the PendingIntent issue.

Refactor the changes introduced in Ib02842bb.

- Now Welcome and AccountSettingsXL accept intents with URLs of the following
style, and get IDs from query params, rather than extras.

Welcome:
content://ui.email.android.com/view/mailbox?ACCOUNT_ID=1&MAILBOX_ID=2&MESSAGE_ID=3

AccountSettingsXL:
content://ui.email.android.com/settings?ACCOUNT_ID=1

- Now the "new message" and "login failed" notifications use these new style
intents, so the system wouldn't merge PendingIntents for different accounts.

Also:
- Moved all notification creation logic to NotificationController.
  (Except the one in CalendarSyncEnabler; which is used only to support
  upgrading from pre-froyo and I don't think it's worth refactoring.)

- Note the "password expired/expiring" and "security needed" notifications
aren't changed; they still use extras to store account IDs.  This is okay
because these notifications are not per-account.

Bug 4065269

Change-Id: I70737438d2e7c45fd7488a5b0a7105c8568e02f7
This commit is contained in:
Makoto Onuki 2011-03-21 17:08:16 -07:00
parent ca64197427
commit 308ce92847
10 changed files with 379 additions and 136 deletions

View File

@ -92,12 +92,20 @@
android:name=".activity.Welcome"
>
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.DEFAULT" />
<category
android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<data
android:scheme="content"
android:host="ui.email.android.com"
android:path="/view/mailbox"
/>
</intent-filter>
</activity>
<!-- Must be exported in order for the AccountManager to launch it -->
@ -154,6 +162,15 @@
<category
android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="content"
android:host="ui.email.android.com"
android:path="/settings"
/>
</intent-filter>
</activity>
<activity
android:name=".activity.setup.AccountSecurity"

View File

@ -34,7 +34,6 @@ import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.graphics.Typeface;
@ -1095,19 +1094,6 @@ public class Utility {
}
}
/**
* Create an {@link Intent} to launch an activity as the main entry point. Existing activities
* will all be closed.
*/
public static Intent createRestartAppIntent(Context context, Class<? extends Activity> clazz) {
Intent i = new Intent(context, clazz);
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return i;
}
/**
* Legacy URI parser. Used in one of three different scenarios:
* 1. Backup / Restore of account

View File

@ -18,6 +18,7 @@ package com.android.email;
import com.android.email.activity.ContactStatusLoader;
import com.android.email.activity.Welcome;
import com.android.email.activity.setup.AccountSecurity;
import com.android.email.activity.setup.AccountSettingsXL;
import com.android.emailcommon.mail.Address;
import com.android.emailcommon.provider.EmailContent;
@ -43,15 +44,15 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Class that manages notifications.
*
* TODO Gather all notification related code here
*/
public class NotificationController {
public static final int NOTIFICATION_ID_SECURITY_NEEDED = 1;
public static final int NOTIFICATION_ID_EXCHANGE_CALENDAR_ADDED = 2;
public static final int NOTIFICATION_ID_ATTACHMENT_WARNING = 3;
public static final int NOTIFICATION_ID_PASSWORD_EXPIRING = 4;
public static final int NOTIFICATION_ID_PASSWORD_EXPIRED = 5;
private static final int NOTIFICATION_ID_SECURITY_NEEDED = 1;
// ID reserved for CalendarSyncEnabler
private static final int PLACEHOLDER_NOTIFICATION_ID_EXCHANGE_CALENDAR_ADDED = 2;
private static final int NOTIFICATION_ID_ATTACHMENT_WARNING = 3;
private static final int NOTIFICATION_ID_PASSWORD_EXPIRING = 4;
private static final int NOTIFICATION_ID_PASSWORD_EXPIRED = 5;
private static final int NOTIFICATION_ID_BASE_NEW_MESSAGES = 0x10000000;
private static final int NOTIFICATION_ID_BASE_LOGIN_WARNING = 0x20000000;
@ -93,13 +94,12 @@ public class NotificationController {
* @param intent The intent to launch from the notification
* @param notificationId The notification id
*/
public void postAccountNotification(Account account, String ticker, String contentTitle,
private void showAccountNotification(Account account, String ticker, String contentTitle,
String contentText, Intent intent, int notificationId) {
// Pending Intent
PendingIntent pending = null;
if (intent != null) {
intent = rewriteForPendingIntent(intent);
pending =
PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@ -137,7 +137,7 @@ public class NotificationController {
* Generic notification canceler.
* @param notificationId The notification id
*/
public void cancelNotification(int notificationId) {
private void cancelNotification(int notificationId) {
mNotificationManager.cancel(notificationId);
}
@ -203,26 +203,6 @@ public class NotificationController {
private static final AtomicInteger sSequenceNumber = new AtomicInteger();
/**
* Rewrite an intent so that it'll always look unique to {@link PendingIntent}.
*
* TODO This should be removed. Instead, use URIs which is unique to each account to open
* activities.
*/
private static Intent rewriteForPendingIntent(Intent original) {
if (original.getComponent() == null) {
return original; // Doesn't have a component set -- can't set a URI.
}
Uri.Builder builder = new Uri.Builder();
builder.scheme("content");
builder.authority("email-dummy");
builder.appendEncodedPath(Integer.toString(sSequenceNumber.incrementAndGet()));
// If a componentName is set, the data part won't be used to resolve an intent.
original.setData(builder.build());
return original;
}
/**
* Create a notification
*
@ -249,7 +229,7 @@ public class NotificationController {
// Intent to open inbox
PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0,
rewriteForPendingIntent(Welcome.createOpenAccountInboxIntent(mContext, accountId)),
Welcome.createOpenAccountInboxIntent(mContext, accountId),
0);
Notification.Builder builder = new Notification.Builder(mContext)
@ -332,7 +312,7 @@ public class NotificationController {
public void showDownloadForwardFailedNotification(Attachment attachment) {
final Account account = Account.restoreAccountWithId(mContext, attachment.mAccountKey);
if (account == null) return;
postAccountNotification(account,
showAccountNotification(account,
mContext.getString(R.string.forward_download_failed_ticker),
mContext.getString(R.string.forward_download_failed_title),
attachment.mFileName,
@ -354,7 +334,7 @@ public class NotificationController {
public void showLoginFailedNotification(long accountId) {
final Account account = Account.restoreAccountWithId(mContext, accountId);
if (account == null) return;
postAccountNotification(account,
showAccountNotification(account,
mContext.getString(R.string.login_failed_ticker, account.mDisplayName),
mContext.getString(R.string.login_failed_title),
account.getDisplayName(),
@ -366,4 +346,69 @@ public class NotificationController {
public void cancelLoginFailedNotification(long accountId) {
mNotificationManager.cancel(getLoginFailedNotificationId(accountId));
}
/**
* Show "password expiring" notification.
*
* Note all accounts share the same notification ID.
*/
public void showPasswordExpiringNotification(long accountId) {
Account account = Account.restoreAccountWithId(mContext, accountId);
if (account == null) return;
Intent intent = AccountSecurity.actionDevicePasswordExpirationIntent(mContext,
accountId, false);
String ticker = mContext.getString(
R.string.password_expire_warning_ticker_fmt, account.getDisplayName());
String contentTitle = mContext.getString(
R.string.password_expire_warning_content_title);
String contentText = account.getDisplayName();
showAccountNotification(account, ticker, contentTitle, contentText, intent,
NOTIFICATION_ID_PASSWORD_EXPIRING);
}
/**
* Show "password expired" notification.
*
* Note all accounts share the same notification ID.
*/
public void showPasswordExpiredNotification(long accountId) {
Account account = Account.restoreAccountWithId(mContext, accountId);
if (account == null) return;
Intent intent = AccountSecurity.actionDevicePasswordExpirationIntent(mContext,
accountId, true);
String ticker = mContext.getString(R.string.password_expired_ticker);
String contentTitle = mContext.getString(R.string.password_expired_content_title);
String contentText = account.getDisplayName();
showAccountNotification(account, ticker, contentTitle,
contentText, intent, NOTIFICATION_ID_PASSWORD_EXPIRED);
}
/**
* Cancel both "password expired/expiring" notifications.
*/
public void cancelPasswordExpirationNotifications() {
cancelNotification(NOTIFICATION_ID_PASSWORD_EXPIRING);
cancelNotification(NOTIFICATION_ID_PASSWORD_EXPIRED);
}
/**
* Show "security needed" notification.
*/
public void showSecurityNeededNotification(Account account) {
String tickerText = mContext.getString(R.string.security_notification_ticker_fmt,
account.getDisplayName());
String contentTitle = mContext.getString(R.string.security_notification_content_title);
String contentText = account.getDisplayName();
Intent intent = AccountSecurity.actionUpdateSecurityIntent(mContext, account.mId, true);
showAccountNotification(
account, tickerText, contentTitle, contentText, intent,
NOTIFICATION_ID_SECURITY_NEEDED);
}
/**
* Cancel "security needed" notification.
*/
public void cancelSecurityNeededNotification() {
cancelNotification(NOTIFICATION_ID_SECURITY_NEEDED);
}
}

View File

@ -502,14 +502,7 @@ public class SecurityPolicy {
setAccountHoldFlag(mContext, account, true);
// Put up a notification
String tickerText = mContext.getString(R.string.security_notification_ticker_fmt,
account.getDisplayName());
String contentTitle = mContext.getString(R.string.security_notification_content_title);
String contentText = account.getDisplayName();
Intent intent = AccountSecurity.actionUpdateSecurityIntent(mContext, accountId, true);
NotificationController.getInstance(mContext).postAccountNotification(
account, tickerText, contentTitle, contentText, intent,
NotificationController.NOTIFICATION_ID_SECURITY_NEEDED);
NotificationController.getInstance(mContext).showSecurityNeededNotification(account);
}
/**
@ -517,8 +510,7 @@ public class SecurityPolicy {
* cleared now.
*/
public void clearNotification(long accountId) {
NotificationController.getInstance(mContext).cancelNotification(
NotificationController.NOTIFICATION_ID_SECURITY_NEEDED);
NotificationController.getInstance(mContext).cancelSecurityNeededNotification();
}
/**
@ -617,34 +609,14 @@ public class SecurityPolicy {
if (!expired) {
// 4. If warning, simply put up a generic notification and report that it came from
// the shortest-expiring account.
Account account = Account.restoreAccountWithId(context, nextExpiringAccountId);
if (account == null) return;
Intent intent = AccountSecurity.actionDevicePasswordExpirationIntent(context,
nextExpiringAccountId, false);
String ticker = context.getString(
R.string.password_expire_warning_ticker_fmt, account.getDisplayName());
String contentTitle = context.getString(
R.string.password_expire_warning_content_title);
String contentText = account.getDisplayName();
NotificationController nc = NotificationController.getInstance(mContext);
nc.postAccountNotification(account, ticker, contentTitle, contentText, intent,
NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRING);
NotificationController.getInstance(mContext).showPasswordExpiringNotification(
nextExpiringAccountId);
} else {
// 5. Actually expired - find all accounts that expire passwords, and wipe them
boolean wiped = wipeExpiredAccounts(context, Controller.getInstance(context));
if (wiped) {
// Post notification
Account account = Account.restoreAccountWithId(context, nextExpiringAccountId);
if (account == null) return;
Intent intent = AccountSecurity.actionDevicePasswordExpirationIntent(context,
nextExpiringAccountId, true);
String ticker = context.getString(R.string.password_expired_ticker);
String contentTitle = context.getString(R.string.password_expired_content_title);
String contentText = account.getDisplayName();
NotificationController nc = NotificationController.getInstance(mContext);
nc.postAccountNotification(account, ticker, contentTitle,
contentText, intent,
NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRED);
NotificationController.getInstance(mContext).showPasswordExpiredNotification(
nextExpiringAccountId);
}
}
}
@ -732,9 +704,7 @@ public class SecurityPolicy {
// Clear security holds (if any)
Account.clearSecurityHoldOnAllAccounts(context);
// Cancel any active notifications (if any are posted)
NotificationController nc = NotificationController.getInstance(context);
nc.cancelNotification(NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRING);
nc.cancelNotification(NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRED);
NotificationController.getInstance(context).cancelPasswordExpirationNotifications();
break;
case DEVICE_ADMIN_MESSAGE_PASSWORD_EXPIRING:
instance.onPasswordExpiring(instance.mContext);

View File

@ -0,0 +1,142 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.activity;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
public final class IntentUtilities {
// Format for activity URIs: content://ui.email.android.com/...
private static final String ACTIVITY_INTENT_SCHEME = "content";
private static final String ACTIVITY_INTENT_HOST = "ui.email.android.com";
private static final String ACCOUNT_ID_PARAM = "ACCOUNT_ID";
private static final String MAILBOX_ID_PARAM = "MAILBOX_ID";
private static final String MESSAGE_ID_PARAM = "MESSAGE_ID";
private IntentUtilities() {
}
/**
* @return a URI builder for "content://ui.email.android.com/..."
*/
public static Uri.Builder createActivityIntentUrlBuilder(String path) {
final Uri.Builder b = new Uri.Builder();
b.scheme(ACTIVITY_INTENT_SCHEME);
b.authority(ACTIVITY_INTENT_HOST);
b.path(path);
return b;
}
/**
* Add the account ID parameter.
*/
public static void setAccountId(Uri.Builder b, long accountId) {
if (accountId != -1) {
b.appendQueryParameter(ACCOUNT_ID_PARAM, Long.toString(accountId));
}
}
/**
* Add the mailbox ID parameter.
*/
public static void setMailboxId(Uri.Builder b, long mailboxId) {
if (mailboxId != -1) {
b.appendQueryParameter(MAILBOX_ID_PARAM, Long.toString(mailboxId));
}
}
/**
* Add the message ID parameter.
*/
public static void setMessageId(Uri.Builder b, long messageId) {
if (messageId != -1) {
b.appendQueryParameter(MESSAGE_ID_PARAM, Long.toString(messageId));
}
}
/**
* Retrieve the account ID.
*/
public static long getAccountIdFromIntent(Intent intent) {
return getLongFromIntent(intent, ACCOUNT_ID_PARAM);
}
/**
* Retrieve the mailbox ID.
*/
public static long getMailboxIdFromIntent(Intent intent) {
return getLongFromIntent(intent, MAILBOX_ID_PARAM);
}
/**
* Retrieve the message ID.
*/
public static long getMessageIdFromIntent(Intent intent) {
return getLongFromIntent(intent, MESSAGE_ID_PARAM);
}
private static long getLongFromIntent(Intent intent, String paramName) {
long value = -1;
if (intent.getData() != null) {
value = getLongParamFromUri(intent.getData(), paramName, -1);
}
return value;
}
private static long getLongParamFromUri(Uri uri, String paramName, long defaultValue) {
final String value = uri.getQueryParameter(paramName);
if (!TextUtils.isEmpty(value)) {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
// return default
}
}
return defaultValue;
}
/**
* Create an {@link Intent} to launch an activity as the main entry point. Existing activities
* will all be closed.
*/
public static Intent createRestartAppIntent(Context context, Class<? extends Activity> clazz) {
Intent i = new Intent(context, clazz);
prepareRestartAppIntent(i);
return i;
}
/**
* Create an {@link Intent} to launch an activity as the main entry point. Existing activities
* will all be closed.
*/
public static Intent createRestartAppIntent(Uri data) {
Intent i = new Intent(Intent.ACTION_MAIN, data);
prepareRestartAppIntent(i);
return i;
}
private static void prepareRestartAppIntent(Intent i) {
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}

View File

@ -31,7 +31,6 @@ import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Mailbox;
import com.android.emailcommon.utility.EmailAsyncTask;
import com.android.emailcommon.utility.Utility;
import android.app.ActionBar;
import android.app.Activity;
@ -103,7 +102,7 @@ public class MessageListXL extends Activity implements
* @param accountId If -1, default account will be used.
*/
public static void actionOpenAccount(Activity fromActivity, long accountId) {
Intent i = Utility.createRestartAppIntent(fromActivity, MessageListXL.class);
Intent i = IntentUtilities.createRestartAppIntent(fromActivity, MessageListXL.class);
if (accountId != -1) {
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
}
@ -121,7 +120,7 @@ public class MessageListXL extends Activity implements
if (accountId == -1 || mailboxId == -1) {
throw new InvalidParameterException();
}
Intent i = Utility.createRestartAppIntent(fromActivity, MessageListXL.class);
Intent i = IntentUtilities.createRestartAppIntent(fromActivity, MessageListXL.class);
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
fromActivity.startActivity(i);
@ -140,7 +139,7 @@ public class MessageListXL extends Activity implements
if (accountId == -1 || mailboxId == -1 || messageId == -1) {
throw new InvalidParameterException();
}
Intent i = Utility.createRestartAppIntent(fromActivity, MessageListXL.class);
Intent i = IntentUtilities.createRestartAppIntent(fromActivity, MessageListXL.class);
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
i.putExtra(EXTRA_MESSAGE_ID, messageId);

View File

@ -24,15 +24,14 @@ import com.android.email.service.MailService;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Mailbox;
import com.android.emailcommon.utility.Utility;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
/**
* The Welcome activity initializes the application and decides what Activity
@ -47,38 +46,32 @@ public class Welcome extends Activity {
* Commands for testing...
* Open 1 pane
adb shell am start -a android.intent.action.MAIN \
-n com.google.android.email/com.android.email.activity.Welcome \
-d '"content://ui.email.android.com/view/mailbox"' \
-e DEBUG_PANE_MODE 1
* Open 2 pane
adb shell am start -a android.intent.action.MAIN \
-n com.google.android.email/com.android.email.activity.Welcome \
-d '"content://ui.email.android.com/view/mailbox"' \
-e DEBUG_PANE_MODE 2
* Open an account (ID=2) in 2 pane
* Open an account (ID=1) in 2 pane
adb shell am start -a android.intent.action.MAIN \
-n com.google.android.email/com.android.email.activity.Welcome \
-e DEBUG_PANE_MODE 2 --el ACCOUNT_ID 2
-d '"content://ui.email.android.com/view/mailbox?ACCOUNT_ID=1"' \
-e DEBUG_PANE_MODE 2
* Open a message (account id=1, mailbox id=2, message id=3)
adb shell am start -a android.intent.action.MAIN \
-n com.google.android.email/com.android.email.activity.Welcome \
-d '"content://ui.email.android.com/view/mailbox?ACCOUNT_ID=1&MAILBOX_ID=2&MESSAGE_ID=3"' \
-e DEBUG_PANE_MODE 2 \
--el ACCOUNT_ID 1 \
--el MAILBOX_ID 2 \
--el MESSAGE_ID 3
*/
private static final String EXTRA_ACCOUNT_ID = "ACCOUNT_ID";
private static final String EXTRA_MAILBOX_ID = "MAILBOX_ID";
private static final String EXTRA_MESSAGE_ID = "MESSAGE_ID";
/**
* Extra for debugging. Set 1 to force one-pane. Set 2 to force two-pane.
*/
private static final String EXTRA_DEBUG_PANE_MODE = "DEBUG_PANE_MODE";
private Handler mHandler = new Handler();
private static final String VIEW_MAILBOX_INTENT_URL_PATH = "/view/mailbox";
/**
* @return true if the two-pane activity should be used on the current configuration.
@ -94,7 +87,7 @@ public class Welcome extends Activity {
* which will drop any other activities on the stack (e.g. AccountFolderList or MessageList).
*/
public static void actionStart(Activity fromActivity) {
Intent i = Utility.createRestartAppIntent(fromActivity, Welcome.class);
Intent i = IntentUtilities.createRestartAppIntent(fromActivity, Welcome.class);
fromActivity.startActivity(i);
}
@ -103,11 +96,10 @@ public class Welcome extends Activity {
* specified account will be automatically be opened when the activity starts.
*/
public static Intent createOpenAccountInboxIntent(Context context, long accountId) {
Intent i = Utility.createRestartAppIntent(context, Welcome.class);
if (accountId != -1) {
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
}
return i;
final Uri.Builder b = IntentUtilities.createActivityIntentUrlBuilder(
VIEW_MAILBOX_INTENT_URL_PATH);
IntentUtilities.setAccountId(b, accountId);
return IntentUtilities.createRestartAppIntent(b.build());
}
/**
@ -115,13 +107,12 @@ public class Welcome extends Activity {
*/
public static Intent createOpenMessageIntent(Context context, long accountId,
long mailboxId, long messageId) {
Intent i = Utility.createRestartAppIntent(context, Welcome.class);
if (accountId != -1) {
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
i.putExtra(EXTRA_MESSAGE_ID, messageId);
}
return i;
final Uri.Builder b = IntentUtilities.createActivityIntentUrlBuilder(
VIEW_MAILBOX_INTENT_URL_PATH);
IntentUtilities.setAccountId(b, accountId);
IntentUtilities.setMailboxId(b, mailboxId);
IntentUtilities.setMessageId(b, messageId);
return IntentUtilities.createRestartAppIntent(b.build());
}
/**
@ -170,9 +161,10 @@ public class Welcome extends Activity {
// TODO More completely separate ExchangeService from Email app
ExchangeUtils.startExchangeService(this);
final long accountId = getIntent().getLongExtra(EXTRA_ACCOUNT_ID, -1);
final long mailboxId = getIntent().getLongExtra(EXTRA_MAILBOX_ID, -1);
final long messageId = getIntent().getLongExtra(EXTRA_MESSAGE_ID, -1);
final Intent intent = getIntent();
final long accountId = IntentUtilities.getAccountIdFromIntent(intent);
final long mailboxId = IntentUtilities.getMailboxIdFromIntent(intent);
final long messageId = IntentUtilities.getMessageIdFromIntent(intent);
final int debugPaneMode = getDebugPaneMode(getIntent());
new MainActivityLauncher(this, accountId, mailboxId, messageId, debugPaneMode).execute();
}

View File

@ -20,6 +20,7 @@ import com.android.email.Controller;
import com.android.email.NotificationController;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.IntentUtilities;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.emailcommon.Logging;
@ -39,6 +40,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceActivity;
@ -66,8 +68,13 @@ import java.util.List;
* dealing with accounts being added/deleted and triggering the header reload.
*/
public class AccountSettingsXL extends PreferenceActivity {
/*
* Intent to open account settings for account=1
adb shell am start -a android.intent.action.EDIT \
-d '"content://ui.email.android.com/settings?ACCOUNT_ID=1"'
*/
// Intent extras for our internal activity launch
/* package */ static final String EXTRA_ACCOUNT_ID = "AccountSettingsXL.account_id";
private static final String EXTRA_ENABLE_DEBUG = "AccountSettingsXL.enable_debug";
private static final String EXTRA_LOGIN_WARNING_FOR_ACCOUNT = "AccountSettingsXL.for_account";
@ -116,9 +123,7 @@ public class AccountSettingsXL extends PreferenceActivity {
* Display (and edit) settings for a specific account, or -1 for any/all accounts
*/
public static void actionSettings(Activity fromActivity, long accountId) {
Intent i = new Intent(fromActivity, AccountSettingsXL.class);
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
fromActivity.startActivity(i);
fromActivity.startActivity(createAccountSettingsIntent(fromActivity, accountId, null));
}
/**
@ -128,9 +133,12 @@ public class AccountSettingsXL extends PreferenceActivity {
*/
public static Intent createAccountSettingsIntent(Context context, long accountId,
String loginWarningAccountName) {
Intent i = new Intent(context, AccountSettingsXL.class);
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
i.putExtra(EXTRA_LOGIN_WARNING_FOR_ACCOUNT, loginWarningAccountName);
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);
}
return i;
}
@ -160,7 +168,7 @@ public class AccountSettingsXL extends PreferenceActivity {
(GetAccountIdFromAccountTask) new GetAccountIdFromAccountTask().execute(i);
} else {
// Otherwise, we're called from within the Email app and look for our extras
mRequestedAccountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
mRequestedAccountId = IntentUtilities.getAccountIdFromIntent(i);
String loginWarningAccount = i.getStringExtra(EXTRA_LOGIN_WARNING_FOR_ACCOUNT);
if (loginWarningAccount != null) {
// Show dialog (first time only - don't re-show on a rotation)

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.activity;
import com.android.email.activity.IntentUtilities;
import android.content.Intent;
import android.net.Uri;
import android.test.AndroidTestCase;
public class IntentUtilitiesTests extends AndroidTestCase {
public void testSimple() {
final Uri.Builder b = IntentUtilities.createActivityIntentUrlBuilder("/abc");
IntentUtilities.setAccountId(b, 10);
IntentUtilities.setMailboxId(b, 20);
IntentUtilities.setMessageId(b, 30);
final Uri u = b.build();
assertEquals("content", u.getScheme());
assertEquals("ui.email.android.com", u.getAuthority());
assertEquals("/abc", u.getPath());
final Intent i = new Intent(Intent.ACTION_MAIN, u);
assertEquals(10, IntentUtilities.getAccountIdFromIntent(i));
assertEquals(20, IntentUtilities.getMailboxIdFromIntent(i));
assertEquals(30, IntentUtilities.getMessageIdFromIntent(i));
}
public void testGetIdFromIntent() {
Intent i;
// No URL in intent
i = new Intent(getContext(), getClass());
assertEquals(-1, IntentUtilities.getAccountIdFromIntent(i));
assertEquals(-1, IntentUtilities.getMailboxIdFromIntent(i));
assertEquals(-1, IntentUtilities.getMessageIdFromIntent(i));
// No param
checkGetIdFromIntent("content://s/", -1);
// No value
checkGetIdFromIntent("content://s/?ID=", -1);
// Value not integer
checkGetIdFromIntent("content://s/?ID=x", -1);
// Negative value
checkGetIdFromIntent("content://s/?ID=-100", -100);
// Normal value
checkGetIdFromIntent("content://s/?ID=200", 200);
// With all 3 params
i = new Intent(Intent.ACTION_VIEW, Uri.parse(
"content://s/?ACCOUNT_ID=5&MAILBOX_ID=6&MESSAGE_ID=7"));
assertEquals(5, IntentUtilities.getAccountIdFromIntent(i));
assertEquals(6, IntentUtilities.getMailboxIdFromIntent(i));
assertEquals(7, IntentUtilities.getMessageIdFromIntent(i));
}
public void checkGetIdFromIntent(String uri, long expected) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(uri.replace("ID", "ACCOUNT_ID")));
assertEquals(expected, IntentUtilities.getAccountIdFromIntent(i));
i = new Intent(Intent.ACTION_VIEW, Uri.parse(uri.replace("ID", "MAILBOX_ID")));
assertEquals(expected, IntentUtilities.getMailboxIdFromIntent(i));
i = new Intent(Intent.ACTION_VIEW, Uri.parse(uri.replace("ID", "MESSAGE_ID")));
assertEquals(expected, IntentUtilities.getMessageIdFromIntent(i));
}
}

View File

@ -16,6 +16,7 @@
package com.android.email.activity.setup;
import com.android.email.activity.IntentUtilities;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.utility.Utility;
@ -169,9 +170,7 @@ public class AccountSettingsXLTests extends ActivityInstrumentationTestCase2<Acc
mAccount.save(mContext);
mAccountId = mAccount.mId;
Intent i = new Intent(Intent.ACTION_MAIN);
i.putExtra(AccountSettingsXL.EXTRA_ACCOUNT_ID, mAccountId);
return i;
return AccountSettingsXL.createAccountSettingsIntent(mContext, mAccountId, null);
}
}