Improvements to default account handling
* Remove all references to Account.mIsDefault, which was not the right way to find the default account (it is lazy initialized) * Change Account.getDefaultAccount to getDefaultAccountId, which is more efficient and suitable in most uses. * Wrote unit tests for provider default account handling This should resolve bug 1983390 as well as a few other issues with default account management.
This commit is contained in:
parent
986a3b5f03
commit
54c1f2bf9a
|
@ -363,9 +363,9 @@ public class AccountFolderList extends ExpandableListActivity {
|
|||
}
|
||||
|
||||
private void onCompose() {
|
||||
EmailContent.Account defaultAccount = EmailContent.Account.getDefaultAccount(this);
|
||||
if (defaultAccount != null) {
|
||||
MessageCompose.actionCompose(this, defaultAccount.mId);
|
||||
long defaultAccountId = Account.getDefaultAccountId(this);
|
||||
if (defaultAccountId != -1) {
|
||||
MessageCompose.actionCompose(this, defaultAccountId);
|
||||
} else {
|
||||
onAddNewAccount();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.EmailAddressAdapter;
|
||||
import com.android.email.EmailAddressValidator;
|
||||
|
@ -23,7 +24,6 @@ import com.android.email.MessagingController;
|
|||
import com.android.email.MessagingListener;
|
||||
import com.android.email.R;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.mail.Address;
|
||||
import com.android.email.mail.Body;
|
||||
import com.android.email.mail.Message;
|
||||
|
@ -32,15 +32,11 @@ import com.android.email.mail.Multipart;
|
|||
import com.android.email.mail.Part;
|
||||
import com.android.email.mail.Message.RecipientType;
|
||||
import com.android.email.mail.internet.EmailHtmlUtil;
|
||||
import com.android.email.mail.internet.MimeBodyPart;
|
||||
import com.android.email.mail.internet.MimeHeader;
|
||||
import com.android.email.mail.internet.MimeMessage;
|
||||
import com.android.email.mail.internet.MimeMultipart;
|
||||
import com.android.email.mail.internet.MimeUtility;
|
||||
import com.android.email.mail.internet.TextBody;
|
||||
import com.android.email.mail.store.LocalStore;
|
||||
import com.android.email.mail.store.LocalStore.LocalAttachmentBody;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
|
@ -81,7 +77,6 @@ import java.io.Serializable;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class MessageCompose extends Activity implements OnClickListener, OnFocusChangeListener {
|
||||
|
@ -117,7 +112,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
|||
private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1;
|
||||
|
||||
private long mAccountId;
|
||||
private EmailContent.Account mAccount;
|
||||
private Account mAccount;
|
||||
private String mFolder;
|
||||
private String mSourceMessageUid;
|
||||
private Message mSourceMessage;
|
||||
|
@ -432,14 +427,16 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
|||
(Intent.ACTION_SEND.equals(action))) {
|
||||
|
||||
// Check first for a valid account
|
||||
mAccount = EmailContent.Account.getDefaultAccount(this);
|
||||
if (mAccount == null) {
|
||||
mAccountId = Account.getDefaultAccountId(this);
|
||||
if (mAccountId == -1) {
|
||||
// There are no accounts set up. This should not have happened. Prompt the
|
||||
// user to set up an account as an acceptable bailout.
|
||||
AccountFolderList.actionShowAccounts(this);
|
||||
mDraftNeedsSaving = false;
|
||||
finish();
|
||||
return;
|
||||
} else {
|
||||
mAccount = Account.restoreAccountWithId(this, mAccountId);
|
||||
}
|
||||
|
||||
// Use the fields found in the Intent to prefill as much of the message as possible
|
||||
|
@ -448,7 +445,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
|||
else {
|
||||
// Otherwise, handle the internal cases (Message Composer invoked from within app)
|
||||
mAccountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
||||
mAccount = EmailContent.Account.restoreAccountWithId(this, mAccountId);
|
||||
mAccount = Account.restoreAccountWithId(this, mAccountId);
|
||||
mFolder = intent.getStringExtra(EXTRA_FOLDER);
|
||||
// TODO: change sourceMessageUid to be long _id instead of String
|
||||
mSourceMessageUid = intent.getStringExtra(EXTRA_MESSAGE);
|
||||
|
@ -1305,19 +1302,19 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
|||
|
||||
class Listener extends MessagingListener {
|
||||
@Override
|
||||
public void loadMessageForViewStarted(EmailContent.Account account, String folder,
|
||||
public void loadMessageForViewStarted(Account account, String folder,
|
||||
String uid) {
|
||||
mHandler.sendEmptyMessage(MSG_PROGRESS_ON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewFinished(EmailContent.Account account, String folder,
|
||||
public void loadMessageForViewFinished(Account account, String folder,
|
||||
String uid, Message message) {
|
||||
mHandler.sendEmptyMessage(MSG_PROGRESS_OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewBodyAvailable(EmailContent.Account account, String folder,
|
||||
public void loadMessageForViewBodyAvailable(Account account, String folder,
|
||||
String uid, final Message message) {
|
||||
mSourceMessage = message;
|
||||
runOnUiThread(new Runnable() {
|
||||
|
@ -1328,14 +1325,14 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
|
|||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewFailed(EmailContent.Account account, String folder, String uid,
|
||||
public void loadMessageForViewFailed(Account account, String folder, String uid,
|
||||
final String message) {
|
||||
mHandler.sendEmptyMessage(MSG_PROGRESS_OFF);
|
||||
// TODO show network error
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageUidChanged(EmailContent.Account account, String folder,String oldUid,
|
||||
public void messageUidChanged(Account account, String folder,String oldUid,
|
||||
String newUid) {
|
||||
if (account.equals(mAccount) && (folder.equals(mFolder)
|
||||
|| (mFolder == null
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.android.email.mail.MessagingException;
|
|||
import com.android.email.mail.Sender;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.HostAuth;
|
||||
|
||||
import android.app.Activity;
|
||||
|
@ -55,7 +56,7 @@ public class AccountSettings extends PreferenceActivity {
|
|||
private static final String PREFERENCE_ADD_ACCOUNT = "add_account";
|
||||
|
||||
private long mAccountId;
|
||||
private EmailContent.Account mAccount;
|
||||
private Account mAccount;
|
||||
private boolean mAccountDirty;
|
||||
|
||||
private EditTextPreference mAccountDescription;
|
||||
|
@ -82,7 +83,7 @@ public class AccountSettings extends PreferenceActivity {
|
|||
|
||||
Intent i = getIntent();
|
||||
mAccountId = getIntent().getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
||||
mAccount = EmailContent.Account.restoreAccountWithId(this, mAccountId);
|
||||
mAccount = Account.restoreAccountWithId(this, mAccountId);
|
||||
mAccountDirty = false;
|
||||
|
||||
addPreferencesFromResource(R.xml.account_settings_preferences);
|
||||
|
@ -158,11 +159,10 @@ public class AccountSettings extends PreferenceActivity {
|
|||
}
|
||||
|
||||
mAccountDefault = (CheckBoxPreference) findPreference(PREFERENCE_DEFAULT);
|
||||
mAccountDefault.setChecked(mAccount.mIsDefault);
|
||||
mAccountDefault.setChecked(mAccount.mId == Account.getDefaultAccountId(this));
|
||||
|
||||
mAccountNotify = (CheckBoxPreference) findPreference(PREFERENCE_NOTIFY);
|
||||
mAccountNotify.setChecked(0 !=
|
||||
(mAccount.getFlags() & EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL));
|
||||
mAccountNotify.setChecked(0 != (mAccount.getFlags() & Account.FLAGS_NOTIFY_NEW_MAIL));
|
||||
|
||||
mAccountRingtone = (RingtonePreference) findPreference(PREFERENCE_RINGTONE);
|
||||
|
||||
|
@ -173,7 +173,7 @@ public class AccountSettings extends PreferenceActivity {
|
|||
|
||||
mAccountVibrate = (CheckBoxPreference) findPreference(PREFERENCE_VIBRATE);
|
||||
mAccountVibrate.setChecked(0 !=
|
||||
(mAccount.getFlags() & EmailContent.Account.FLAGS_VIBRATE));
|
||||
(mAccount.getFlags() & Account.FLAGS_VIBRATE));
|
||||
|
||||
findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener(
|
||||
new Preference.OnPreferenceClickListener() {
|
||||
|
@ -237,18 +237,18 @@ public class AccountSettings extends PreferenceActivity {
|
|||
|
||||
private void saveSettings() {
|
||||
int newFlags = mAccount.getFlags() &
|
||||
~(EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL | EmailContent.Account.FLAGS_VIBRATE);
|
||||
~(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_VIBRATE);
|
||||
|
||||
mAccount.setDefaultAccount(mAccountDefault.isChecked());
|
||||
mAccount.setDescription(mAccountDescription.getText());
|
||||
mAccount.setName(mAccountName.getText());
|
||||
newFlags |= mAccountNotify.isChecked() ? EmailContent.Account.FLAGS_NOTIFY_NEW_MAIL : 0;
|
||||
newFlags |= mAccountNotify.isChecked() ? Account.FLAGS_NOTIFY_NEW_MAIL : 0;
|
||||
mAccount.setAutomaticCheckIntervalMinutes(Integer.parseInt(mCheckFrequency.getValue()));
|
||||
if (mSyncWindow != null)
|
||||
{
|
||||
mAccount.setSyncWindow(Integer.parseInt(mSyncWindow.getValue()));
|
||||
}
|
||||
newFlags |= mAccountVibrate.isChecked() ? EmailContent.Account.FLAGS_VIBRATE : 0;
|
||||
newFlags |= mAccountVibrate.isChecked() ? Account.FLAGS_VIBRATE : 0;
|
||||
SharedPreferences prefs = mAccountRingtone.getPreferenceManager().getSharedPreferences();
|
||||
mAccount.setRingtone(prefs.getString(PREFERENCE_RINGTONE, null));
|
||||
mAccount.setFlags(newFlags);
|
||||
|
@ -272,7 +272,7 @@ public class AccountSettings extends PreferenceActivity {
|
|||
Class<? extends android.app.Activity> setting = store.getSettingActivityClass();
|
||||
if (setting != null) {
|
||||
java.lang.reflect.Method m = setting.getMethod("actionEditIncomingSettings",
|
||||
android.app.Activity.class, EmailContent.Account.class);
|
||||
android.app.Activity.class, Account.class);
|
||||
m.invoke(null, this, mAccount);
|
||||
mAccountDirty = true;
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ public class AccountSettings extends PreferenceActivity {
|
|||
Class<? extends android.app.Activity> setting = sender.getSettingActivityClass();
|
||||
if (setting != null) {
|
||||
java.lang.reflect.Method m = setting.getMethod("actionEditOutgoingSettings",
|
||||
android.app.Activity.class, EmailContent.Account.class);
|
||||
android.app.Activity.class, Account.class);
|
||||
m.invoke(null, this, mAccount);
|
||||
mAccountDirty = true;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.android.email.Utility;
|
|||
import com.android.email.activity.Debug;
|
||||
import com.android.email.activity.FolderMessageList;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
|
@ -182,9 +183,12 @@ public class AccountSetupBasics extends Activity
|
|||
}
|
||||
|
||||
if (name == null || name.length() == 0) {
|
||||
EmailContent.Account account = EmailContent.Account.getDefaultAccount(this);
|
||||
if (account != null) {
|
||||
name = account.getName();
|
||||
long defaultId = Account.getDefaultAccountId(this);
|
||||
if (defaultId != -1) {
|
||||
Account account = Account.restoreAccountWithId(this, defaultId);
|
||||
if (account != null) {
|
||||
name = account.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
|
|
|
@ -95,6 +95,8 @@ public class AccountSetupOptions extends Activity implements OnClickListener {
|
|||
enableEASSyncWindowSpinner();
|
||||
}
|
||||
|
||||
// Note: It is OK to use mAccount.mIsDefault here *only* because the account
|
||||
// has not been written to the DB yet. Ordinarily, call Account.getDefaultAccountId().
|
||||
if (mAccount.mIsDefault || makeDefault) {
|
||||
mDefaultView.setChecked(true);
|
||||
}
|
||||
|
|
|
@ -797,7 +797,7 @@ public abstract class EmailContent {
|
|||
public long mHostAuthKeyRecv;
|
||||
public long mHostAuthKeySend;
|
||||
public int mFlags;
|
||||
public boolean mIsDefault;
|
||||
public boolean mIsDefault; // note: callers should use getDefaultAccountId()
|
||||
public String mCompatibilityUuid;
|
||||
public String mSenderName;
|
||||
public String mRingtoneUri;
|
||||
|
@ -838,6 +838,13 @@ public abstract class EmailContent {
|
|||
RECORD_ID
|
||||
};
|
||||
|
||||
/**
|
||||
* This projection is for searching for the default account
|
||||
*/
|
||||
private static final String[] DEFAULT_ID_PROJECTION = new String[] {
|
||||
RECORD_ID, IS_DEFAULT
|
||||
};
|
||||
|
||||
/**
|
||||
* no public constructor since this is a utility class
|
||||
*/
|
||||
|
@ -1151,31 +1158,37 @@ public abstract class EmailContent {
|
|||
mIsDefault = newDefaultState;
|
||||
}
|
||||
|
||||
static private Account getAccountWhere(Context context, String where) {
|
||||
Cursor cursor = context.getContentResolver().query(CONTENT_URI, CONTENT_PROJECTION,
|
||||
/**
|
||||
* Helper method for finding the default account.
|
||||
*/
|
||||
static private long getDefaultAccountWhere(Context context, String where) {
|
||||
Cursor cursor = context.getContentResolver().query(CONTENT_URI,
|
||||
DEFAULT_ID_PROJECTION,
|
||||
where, null, null);
|
||||
try {
|
||||
if (cursor.moveToFirst()) {
|
||||
return getContent(cursor, Account.class);
|
||||
return cursor.getLong(0); // column 0 is id
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
return null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default Account; if one hasn't been explicitly specified, return the first
|
||||
* account found in the database.
|
||||
* @param context
|
||||
* @return the default Account (or none, if there are no accounts)
|
||||
* Return the id of the default account. If one hasn't been explicitly specified, return
|
||||
* the first one in the database. For any account saved in the DB, this must be used
|
||||
* to check for the default account - the mIsDefault field is set lazily and may be
|
||||
* incorrect.
|
||||
* @param context the caller's context
|
||||
* @return the id of the default account, or -1 if there are no accounts
|
||||
*/
|
||||
static public Account getDefaultAccount(Context context) {
|
||||
Account acct = getAccountWhere(context, AccountColumns.IS_DEFAULT + "=1");
|
||||
if (acct == null) {
|
||||
acct = getAccountWhere(context, null);
|
||||
static public long getDefaultAccountId(Context context) {
|
||||
long id = getDefaultAccountWhere(context, AccountColumns.IS_DEFAULT + "=1");
|
||||
if (id == -1) {
|
||||
id = getDefaultAccountWhere(context, null);
|
||||
}
|
||||
return acct;
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.android.email.mail.Message.RecipientType;
|
|||
import com.android.email.mail.internet.MimeMessage;
|
||||
import com.android.email.mail.internet.TextBody;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -104,7 +105,9 @@ public class MessageComposeInstrumentationTests
|
|||
super.setUp();
|
||||
Context context = getInstrumentation().getTargetContext();
|
||||
|
||||
EmailContent.Account.getDefaultAccount(context);
|
||||
// Force assignment of a default account
|
||||
long accountId = Account.getDefaultAccountId(context);
|
||||
Account.restoreAccountWithId(context, accountId);
|
||||
Email.setServicesEnabled(context);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.android.email.MessagingController;
|
|||
import com.android.email.R;
|
||||
import com.android.email.mail.internet.BinaryTempFileBody;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
@ -75,9 +76,9 @@ public class MessageViewTests
|
|||
super.setUp();
|
||||
|
||||
mContext = getInstrumentation().getTargetContext();
|
||||
// force assignment of a default account
|
||||
mAccount = EmailContent.Account.getDefaultAccount(mContext);
|
||||
mAccountId = mAccount.mId;
|
||||
// Force assignment of a default account, and retrieve it
|
||||
mAccountId = Account.getDefaultAccountId(mContext);
|
||||
mAccount = Account.restoreAccountWithId(mContext, mAccountId);
|
||||
Email.setServicesEnabled(mContext);
|
||||
|
||||
// setup an intent to spin up this activity with something useful
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.android.email.mail.MessageTestUtils.MultipartBuilder;
|
|||
import com.android.email.mail.MessageTestUtils.TextBuilder;
|
||||
import com.android.email.mail.store.LocalStore;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.test.AndroidTestCase;
|
||||
|
@ -43,7 +44,8 @@ public class EmailHtmlUtilTest extends AndroidTestCase {
|
|||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
// Force assignment of a default account, and retrieve it
|
||||
mAccount = EmailContent.Account.getDefaultAccount(getContext());
|
||||
long accountId = Account.getDefaultAccountId(getContext());
|
||||
mAccount = Account.restoreAccountWithId(getContext(), accountId);
|
||||
|
||||
// This is needed for mime image bodypart.
|
||||
BinaryTempFileBody.setTempDirectory(getContext().getCacheDir());
|
||||
|
|
|
@ -649,4 +649,54 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests of default account behavior
|
||||
*
|
||||
* 1. Simple set/get
|
||||
* 2. Moving default between 3 accounts
|
||||
* 3. Delete default, make sure another becomes default
|
||||
*/
|
||||
public void testSetGetDefaultAccount() {
|
||||
// There should be no default account if there are no accounts
|
||||
long defaultAccountId = Account.getDefaultAccountId(mMockContext);
|
||||
assertEquals(-1, defaultAccountId);
|
||||
|
||||
Account account1 = ProviderTestUtils.setupAccount("account-default-1", true, mMockContext);
|
||||
long account1Id = account1.mId;
|
||||
Account account2 = ProviderTestUtils.setupAccount("account-default-2", true, mMockContext);
|
||||
long account2Id = account2.mId;
|
||||
Account account3 = ProviderTestUtils.setupAccount("account-default-3", true, mMockContext);
|
||||
long account3Id = account3.mId;
|
||||
|
||||
account1.setDefaultAccount(true);
|
||||
account1.saveOrUpdate(mMockContext);
|
||||
defaultAccountId = Account.getDefaultAccountId(mMockContext);
|
||||
assertEquals(account1Id, defaultAccountId);
|
||||
|
||||
account2.setDefaultAccount(true);
|
||||
account2.saveOrUpdate(mMockContext);
|
||||
defaultAccountId = Account.getDefaultAccountId(mMockContext);
|
||||
assertEquals(account2Id, defaultAccountId);
|
||||
|
||||
account3.setDefaultAccount(true);
|
||||
account3.saveOrUpdate(mMockContext);
|
||||
defaultAccountId = Account.getDefaultAccountId(mMockContext);
|
||||
assertEquals(account3Id, defaultAccountId);
|
||||
|
||||
// Now delete a non-default account and confirm no change
|
||||
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
|
||||
mMockContext.getContentResolver().delete(uri, null, null);
|
||||
|
||||
defaultAccountId = Account.getDefaultAccountId(mMockContext);
|
||||
assertEquals(account3Id, defaultAccountId);
|
||||
|
||||
// Now confirm deleting the default account and it switches to another one
|
||||
uri = ContentUris.withAppendedId(Account.CONTENT_URI, account3Id);
|
||||
mMockContext.getContentResolver().delete(uri, null, null);
|
||||
|
||||
defaultAccountId = Account.getDefaultAccountId(mMockContext);
|
||||
assertEquals(account2Id, defaultAccountId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue