Merge "Properly handle old style (<= 1.6) account shortcuts." into froyo

This commit is contained in:
Makoto Onuki 2010-03-26 14:59:44 -07:00 committed by Android (Google) Code Review
commit 34cd4cadf3
7 changed files with 161 additions and 209 deletions

View File

@ -171,6 +171,23 @@
</intent-filter> </intent-filter>
</activity> </activity>
<!--
This activity catches shortcuts to account created on Android 1.6 and before,
and redirects to MessageList.
singleTask is necessary to make sure the activity is really launched.
Without it, the framework brings up the app to front, but doesn't necessarily
launch the activity.
-->
<activity
android:name=".activity.FolderMessageList"
android:launchMode="singleTask"
>
<intent-filter>
<!-- This action is only to allow an entry point for launcher shortcuts -->
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity <activity
android:name=".activity.MessageView" android:name=".activity.MessageView"
android:theme="@android:style/Theme.NoTitleBar" > android:theme="@android:style/Theme.NoTitleBar" >

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2010 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.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
/**
* An activity to handle old-style (Android <= 1.6) desktop shortcut.
*/
public class FolderMessageList extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
openInbox();
return null;
}
@Override
protected void onPostExecute(Void result) {
finish();
}
}.execute();
}
private void openInbox() {
// If it's the first time, we need to upgrade all accounts.
if (UpgradeAccounts.doBulkUpgradeIfNecessary(this)) {
return;
}
Uri uri = getIntent().getData();
// Verify the format.
if (uri == null || !"content".equals(uri.getScheme())
|| !"accounts".equals(uri.getAuthority())) {
return;
}
String uuid = uri.getPath();
if (uuid.length() > 0) {
uuid = uuid.substring(1); // remove the beginning '/'.
}
if (TextUtils.isEmpty(uuid)) {
return;
}
MessageList.actionOpenAccountInboxUuid(this, uuid);
}
}

View File

@ -180,6 +180,16 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
context.startActivity(createIntent(context, accountId, -1, mailboxType)); context.startActivity(createIntent(context, accountId, -1, mailboxType));
} }
/**
* Open the inbox of the account with a UUID. It's used to handle old style
* (Android <= 1.6) desktop shortcut intents.
*/
public static void actionOpenAccountInboxUuid(Context context, String accountUuid) {
Intent i = createIntent(context, -1, -1, Mailbox.TYPE_INBOX);
i.setData(Account.getShortcutSafeUriFromUuid(accountUuid));
context.startActivity(i);
}
/** /**
* Return an intent to open a specific mailbox by account & type. * Return an intent to open a specific mailbox by account & type.
* *

View File

@ -76,6 +76,9 @@ import java.util.HashSet;
*/ */
public class UpgradeAccounts extends ListActivity implements OnClickListener { public class UpgradeAccounts extends ListActivity implements OnClickListener {
/** DO NOT CHECK IN AS 'TRUE' - DEVELOPMENT ONLY */
private static final boolean DEBUG_FORCE_UPGRADES = false;
private AccountInfo[] mLegacyAccounts; private AccountInfo[] mLegacyAccounts;
private UIHandler mHandler = new UIHandler(); private UIHandler mHandler = new UIHandler();
private AccountsAdapter mAdapter; private AccountsAdapter mAdapter;
@ -90,9 +93,9 @@ public class UpgradeAccounts extends ListActivity implements OnClickListener {
/** This projection is for looking up accounts by their legacy UUID */ /** This projection is for looking up accounts by their legacy UUID */
private static final String WHERE_ACCOUNT_UUID_IS = AccountColumns.COMPATIBILITY_UUID + "=?"; private static final String WHERE_ACCOUNT_UUID_IS = AccountColumns.COMPATIBILITY_UUID + "=?";
public static void actionStart(Activity fromActivity) { public static void actionStart(Context context) {
Intent i = new Intent(fromActivity, UpgradeAccounts.class); Intent i = new Intent(context, UpgradeAccounts.class);
fromActivity.startActivity(i); context.startActivity(i);
} }
@Override @Override
@ -777,4 +780,55 @@ public class UpgradeAccounts extends ListActivity implements OnClickListener {
// optional TLS - TBD // optional TLS - TBD
} }
} }
/**
* Bulk upgrade old accounts if exist.
*
* @return true if bulk upgrade has started. false otherwise.
*/
/* package */ static boolean doBulkUpgradeIfNecessary(Context context) {
if (bulkUpgradesRequired(context, Preferences.getPreferences(context))) {
UpgradeAccounts.actionStart(context);
return true;
}
return false;
}
/**
* Test for bulk upgrades and return true if necessary
*
* TODO should be in an AsyncTask since it has DB ops
*
* @return true if upgrades required (old accounts exist). false otherwise.
*/
private static boolean bulkUpgradesRequired(Context context, Preferences preferences) {
if (DEBUG_FORCE_UPGRADES) {
// build at least one fake account
Account fake = new Account(context);
fake.setDescription("Fake Account");
fake.setEmail("user@gmail.com");
fake.setName("First Last");
fake.setSenderUri("smtp://user:password@smtp.gmail.com");
fake.setStoreUri("imap://user:password@imap.gmail.com");
fake.save(preferences);
return true;
}
// 1. Get list of legacy accounts and look for any non-backup entries
Account[] legacyAccounts = preferences.getAccounts();
if (legacyAccounts.length == 0) {
return false;
}
// 2. Look at the first legacy account and decide what to do
// We only need to look at the first: If it's not a backup account, then it's a true
// legacy account, and there are one or more accounts needing upgrade. If it is a backup
// account, then we know for sure that there are no legacy accounts (backup deletes all
// old accounts, and indicates that "modern" code has already run on this device.)
if (0 != (legacyAccounts[0].getBackupFlags() & Account.BACKUP_FLAGS_IS_BACKUP)) {
return false;
} else {
return true;
}
}
} }

View File

@ -42,9 +42,6 @@ import android.os.Bundle;
*/ */
public class Welcome extends Activity { public class Welcome extends Activity {
/** DO NOT CHECK IN AS 'TRUE' - DEVELOPMENT ONLY */
private static final boolean DEBUG_FORCE_UPGRADES = false;
public static void actionStart(Activity fromActivity) { public static void actionStart(Activity fromActivity) {
Intent i = new Intent(fromActivity, Welcome.class); Intent i = new Intent(fromActivity, Welcome.class);
fromActivity.startActivity(i); fromActivity.startActivity(i);
@ -56,8 +53,7 @@ public class Welcome extends Activity {
// Quickly check for bulk upgrades (from older app versions) and switch to the // Quickly check for bulk upgrades (from older app versions) and switch to the
// upgrade activity if necessary // upgrade activity if necessary
if (bulkUpgradesRequired(this, Preferences.getPreferences(this))) { if (UpgradeAccounts.doBulkUpgradeIfNecessary(this)) {
UpgradeAccounts.actionStart(this);
finish(); finish();
return; return;
} }
@ -104,42 +100,4 @@ public class Welcome extends Activity {
// In all cases, do not return to this activity // In all cases, do not return to this activity
finish(); finish();
} }
/**
* Test for bulk upgrades and return true if necessary
*
* TODO should be in an AsyncTask since it has DB ops
*
* @return true if upgrades required (old accounts exit). false otherwise.
*/
/* package */ boolean bulkUpgradesRequired(Context context, Preferences preferences) {
if (DEBUG_FORCE_UPGRADES) {
// build at least one fake account
Account fake = new Account(this);
fake.setDescription("Fake Account");
fake.setEmail("user@gmail.com");
fake.setName("First Last");
fake.setSenderUri("smtp://user:password@smtp.gmail.com");
fake.setStoreUri("imap://user:password@imap.gmail.com");
fake.save(preferences);
return true;
}
// 1. Get list of legacy accounts and look for any non-backup entries
Account[] legacyAccounts = preferences.getAccounts();
if (legacyAccounts.length == 0) {
return false;
}
// 2. Look at the first legacy account and decide what to do
// We only need to look at the first: If it's not a backup account, then it's a true
// legacy account, and there are one or more accounts needing upgrade. If it is a backup
// account, then we know for sure that there are no legacy accounts (backup deletes all
// old accounts, and indicates that "modern" code has already run on this device.)
if (0 != (legacyAccounts[0].getBackupFlags() & Account.BACKUP_FLAGS_IS_BACKUP)) {
return false;
} else {
return true;
}
}
} }

View File

@ -1279,7 +1279,14 @@ public abstract class EmailContent {
* {@link com.android.email.AccountBackupRestore} won't preserve it. * {@link com.android.email.AccountBackupRestore} won't preserve it.
*/ */
public Uri getShortcutSafeUri() { public Uri getShortcutSafeUri() {
return CONTENT_URI.buildUpon().appendEncodedPath(mCompatibilityUuid).build(); return getShortcutSafeUriFromUuid(mCompatibilityUuid);
}
/**
* @return {@link Uri} to an {@link Account} with a {@code uuid}.
*/
public static Uri getShortcutSafeUriFromUuid(String uuid) {
return CONTENT_URI.buildUpon().appendEncodedPath(uuid).build();
} }
/** /**

View File

@ -1,162 +0,0 @@
/*
* Copyright (C) 2008 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.provider.EmailContent;
import android.content.ContentUris;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
/**
* This is a series of unit tests for the FolderMessageList class.
*
* This is just unit tests of simple statics - the activity is not instantiated
*/
@SmallTest
public class FolderMessageListUnitTests extends AndroidTestCase {
private long mAccountId;
private EmailContent.Account mAccount;
/**
* Delete any dummy accounts we set up for this test
*/
@Override
protected void tearDown() throws Exception {
if (mAccount != null) {
Uri uri = ContentUris.withAppendedId(
EmailContent.Account.CONTENT_URI, mAccountId);
getContext().getContentResolver().delete(uri, null, null);
}
// must call last because it scrubs member variables
super.tearDown();
}
// /**
// * Test of actionHandleAccount() variants. Make sure they generate correct intents and
// * then call startActivity() with them.
// */
// public void testActionHandleAccount() {
// // Create a dummy account
// createTestAccount();
//
// // Create a mock context to catch the startActivity calls
// MyContext mockContext = new MyContext(getContext());
//
// // First, try with no initial folder
// FolderMessageList.actionHandleAccount(mockContext, mAccountId);
// Intent i = mockContext.startActivityIntent;
// assertNotNull(i);
// checkIntent(i, null, mAccount, null);
//
// // Next try with initial folder specified
// FolderMessageList.actionHandleAccount(mockContext, mAccountId, "test-folder-name");
// i = mockContext.startActivityIntent;
// assertNotNull(i);
// checkIntent(i, null, mAccount, "test-folder-name");
// }
/**
* Test of actionHandleAccountIntent(). Make sure it generates correct intents.
*/
// public void testActionHandleAccountIntent() {
// // Create a dummy account
// createTestAccount();
//
// // First try with no initial folder
// Intent result = FolderMessageList.actionHandleAccountIntent(
// getContext(), mAccountId, null);
// checkIntent(result, null, mAccount, null);
//
// // now try with a specified initial folder
// result = FolderMessageList.actionHandleAccountIntent(
// getContext(), mAccountId, "test-folder-name");
// checkIntent(result, null, mAccount, "test-folder-name");
// }
/**
* Test of actionHandleAccountUriIntent(). Make sure it generates correct intents.
*/
// public void testActionHandleAccountUriIntent() {
// // Create a dummy account
// createTestAccount();
// Uri uri = ContentUris.withAppendedId(EmailContent.Account.CONTENT_URI, mAccountId);
//
// // First try with no initial folder
// Intent result = FolderMessageList.actionHandleAccountUriIntent(
// getContext(), mAccountId, null);
// checkIntent(result, uri, null, null);
//
// // now try with a specified initial folder
// result = FolderMessageList.actionHandleAccountUriIntent(
// getContext(), mAccountId, "test-folder-name");
// checkIntent(result, uri, null, "test-folder-name");
// }
/**
* Check the values in a generated intent
*/
private void checkIntent(Intent i,
Uri expectData, EmailContent.Account expectAccount, String expectFolder) {
Uri resultUri = i.getData();
assertEquals(expectData, resultUri);
long resultAccountId = i.getLongExtra("account", -1);
long expectAccountId = (expectAccount != null) ? expectAccount.mId : -1;
assertEquals(expectAccountId, resultAccountId);
String resultFolder = i.getStringExtra("initialFolder");
assertEquals(expectFolder, resultFolder);
}
/**
* Create a dummy account with minimal fields
*/
private void createTestAccount() {
mAccount = new EmailContent.Account();
mAccount.save(getContext());
mAccountId = mAccount.mId;
}
/**
* Mock Context so we can catch the startActivity call in actionHandleAccount()
*/
private static class MyContext extends ContextWrapper {
Intent startActivityIntent = null;
public MyContext(Context base) {
super(base);
}
@Override
public void startActivity(Intent i) {
startActivityIntent = i;
}
}
}