resolve merge conflicts of 949d4e8 to master
Change-Id: I399652b6a1b756a8045c1fef092d10581d56400d
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 80c59dc..4a72fe5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -506,10 +506,5 @@
<meta-data android:name="android.nfc.disable_beam_default" android:value="true" />
- <receiver android:name="com.android.contacts.editor.AccountsChangedBroadcastReceiver">
- <intent-filter>
- <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
- </intent-filter>
- </receiver>
</application>
</manifest>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index ac46a55..d3c4966 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -63,9 +63,6 @@
<!-- Contacts preferences key for contact editor default account -->
<string name="contact_editor_default_account_key">ContactEditorUtils_default_account</string>
- <!-- Contacts preferences key for contact editor anything saved -->
- <string name="contact_editor_anything_saved_key">ContactEditorUtils_anything_saved</string>
-
<!-- The type of VCard for export. If you want to let the app emit vCard which is
specific to some vendor (like DoCoMo), specify this type (e.g. "docomo") -->
<string name="config_export_vcard_type" translatable="false">default</string>
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 1abbecf..096349c 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -344,15 +344,15 @@
private void selectAccountAndCreateContact() {
// If there is no default account or the accounts have changed such that we need to
// prompt the user again, then launch the account prompt.
- final ContactEditorUtils editorUtils = ContactEditorUtils.getInstance(this);
+ final ContactEditorUtils editorUtils = ContactEditorUtils.create(this);
if (editorUtils.shouldShowAccountChangedNotification()) {
Intent intent = new Intent(this, ContactEditorAccountsChangedActivity.class);
startActivityForResult(intent, REQUEST_PICK_DEFAULT_ACCOUNT_FOR_NEW_CONTACT);
} else {
- // Otherwise, there should be a default account. Then either create a local contact
+ // Otherwise, there should be a default account. Then either create a null contact
// (if default account is null) or create a contact with the specified account.
- AccountWithDataSet defaultAccount = editorUtils.getDefaultAccount();
- createNewRawContact(defaultAccount);
+ final AccountWithDataSet targetAccount = editorUtils.getOnlyOrDefaultAccount();
+ createNewRawContact(targetAccount);
}
}
diff --git a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
index 9b211ab..c2ec4ac 100644
--- a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
@@ -79,7 +79,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mEditorUtils = ContactEditorUtils.getInstance(this);
+ mEditorUtils = ContactEditorUtils.create(this);
final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this).
getAccounts(true);
final int numAccounts = accounts.size();
@@ -106,7 +106,7 @@
AccountListFilter.ACCOUNTS_CONTACT_WRITABLE);
accountListView.setAdapter(mAccountListAdapter);
accountListView.setOnItemClickListener(mAccountListItemClickListener);
- } else if (numAccounts == 1 && !accounts.get(0).isLocalAccount()) {
+ } else if (numAccounts == 1 && !accounts.get(0).isNullAccount()) {
// If the user has 1 writable account we will just show the user a message with 2
// possible action buttons.
view = View.inflate(this,
@@ -154,7 +154,7 @@
public void onClick(View v) {
// Remember that the user wants to create local contacts, so the user is not
// prompted again with this activity.
- mEditorUtils.saveDefaultAndAllAccounts(null);
+ mEditorUtils.saveDefaultAccount(AccountWithDataSet.getNullAccount());
setResult(RESULT_OK);
finish();
}
@@ -199,7 +199,7 @@
private void saveAccountAndReturnResult(AccountWithDataSet account) {
// Save this as the default account
- mEditorUtils.saveDefaultAndAllAccounts(account);
+ mEditorUtils.saveDefaultAccount(account);
// Pass account info in activity result intent
Intent intent = new Intent();
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index bd106df..df3f65d 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -575,7 +575,7 @@
if (allAccounts.size() > 1) {
return true;
}
- return !allAccounts.get(0).isLocalAccount();
+ return !allAccounts.get(0).isNullAccount();
}
private void invalidateOptionsMenuIfNeeded() {
diff --git a/src/com/android/contacts/common/model/account/AccountWithDataSet.java b/src/com/android/contacts/common/model/account/AccountWithDataSet.java
index ecd8f27..187f71c 100644
--- a/src/com/android/contacts/common/model/account/AccountWithDataSet.java
+++ b/src/com/android/contacts/common/model/account/AccountWithDataSet.java
@@ -77,13 +77,11 @@
mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet);
}
- // TODO: consider modifying or deleting this method. "local" accounts on some non-nexus devices
- // have non-null values for name, type, and dataset
- public boolean isLocalAccount() {
+ public boolean isNullAccount() {
return name == null && type == null && dataSet == null;
}
- public static AccountWithDataSet getLocalAccount() {
+ public static AccountWithDataSet getNullAccount() {
return new AccountWithDataSet(null, null, null);
}
@@ -126,7 +124,7 @@
public boolean hasData(Context context) {
String selection;
String[] args = null;
- if (isLocalAccount()) {
+ if (isNullAccount()) {
selection = LOCAL_ACCOUNT_SELECTION;
} else {
final String BASE_SELECTION =
diff --git a/src/com/android/contacts/common/preference/ContactsPreferences.java b/src/com/android/contacts/common/preference/ContactsPreferences.java
index f994d28..f4187eb 100644
--- a/src/com/android/contacts/common/preference/ContactsPreferences.java
+++ b/src/com/android/contacts/common/preference/ContactsPreferences.java
@@ -25,10 +25,13 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import com.android.contacts.common.R;
@@ -92,18 +95,24 @@
private ChangeListener mListener = null;
private Handler mHandler;
private final SharedPreferences mPreferences;
+ private final boolean mIsDefaultAccountUserChangeable;
private String mDefaultAccountKey;
- private String mDefaultAccountSavedKey;
public ContactsPreferences(Context context) {
+ this(context,
+ context.getResources().getBoolean(R.bool.config_default_account_user_changeable));
+ }
+
+ @VisibleForTesting
+ ContactsPreferences(Context context, boolean isDefaultAccountUserChangeable) {
mContext = context;
- mHandler = new Handler();
+ mIsDefaultAccountUserChangeable = isDefaultAccountUserChangeable;
+
+ mHandler = new Handler(Looper.getMainLooper());
mPreferences = mContext.getSharedPreferences(context.getPackageName(),
Context.MODE_PRIVATE);
mDefaultAccountKey = mContext.getResources().getString(
R.string.contact_editor_default_account_key);
- mDefaultAccountSavedKey = mContext.getResources().getString(
- R.string.contact_editor_anything_saved_key);
maybeMigrateSystemSettings();
}
@@ -166,7 +175,7 @@
}
public boolean isDefaultAccountUserChangeable() {
- return mContext.getResources().getBoolean(R.bool.config_default_account_user_changeable);
+ return mIsDefaultAccountUserChangeable;
}
public AccountWithDataSet getDefaultAccount() {
@@ -183,16 +192,56 @@
return mDefaultAccount;
}
- public void setDefaultAccount(AccountWithDataSet accountWithDataSet) {
- mDefaultAccount = accountWithDataSet;
- final Editor editor = mPreferences.edit();
- if (mDefaultAccount == null) {
- editor.remove(mDefaultAccountKey);
- } else {
- editor.putString(mDefaultAccountKey, accountWithDataSet.stringify());
+ public void clearDefaultAccount() {
+ mDefaultAccount = null;
+ mPreferences.edit().remove(mDefaultAccountKey).commit();
+ }
+
+ public void setDefaultAccount(@NonNull AccountWithDataSet accountWithDataSet) {
+ if (accountWithDataSet == null) {
+ throw new IllegalArgumentException(
+ "argument should not be null");
}
- editor.putBoolean(mDefaultAccountSavedKey, true);
- editor.commit();
+ mDefaultAccount = accountWithDataSet;
+ mPreferences.edit().putString(mDefaultAccountKey, accountWithDataSet.stringify()).commit();
+ }
+
+ /**
+ * @return false if there is only one writable account or no requirement to return true is met.
+ * true if the contact editor should show the "accounts changed" notification, that is:
+ * - If it's the first launch.
+ * - Or, if the default account has been removed.
+ * (And some extra sanity check)
+ *
+ * Note if this method returns {@code false}, the caller can safely assume that
+ * {@link #getDefaultAccount} will return a valid account. (Either an account which still
+ * exists, or {@code null} which should be interpreted as "local only".)
+ */
+ public boolean shouldShowAccountChangedNotification(List<AccountWithDataSet>
+ currentWritableAccounts) {
+ final AccountWithDataSet defaultAccount = getDefaultAccount();
+
+ // This shouldn't occur anymore because a "device" account is added in the case that there
+ // are no other accounts but if there are no writable accounts then the default has been
+ // initialized if it is "device"
+ if (currentWritableAccounts.isEmpty()) {
+ return defaultAccount == null || !defaultAccount.isNullAccount();
+ }
+
+ if (currentWritableAccounts.size() == 1) {
+ return false;
+ }
+
+ if (defaultAccount == null) {
+ return true;
+ }
+
+ if (!currentWritableAccounts.contains(defaultAccount)) {
+ return true;
+ }
+
+ // All good.
+ return false;
}
public String getContactMetadataSyncAccountName() {
diff --git a/src/com/android/contacts/common/preference/DefaultAccountPreference.java b/src/com/android/contacts/common/preference/DefaultAccountPreference.java
index 3960e62..0fcc8cb 100644
--- a/src/com/android/contacts/common/preference/DefaultAccountPreference.java
+++ b/src/com/android/contacts/common/preference/DefaultAccountPreference.java
@@ -23,6 +23,7 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountDisplayInfoFactory;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.AccountsListAdapter;
@@ -31,6 +32,7 @@
private ContactsPreferences mPreferences;
private AccountsListAdapter mListAdapter;
private AccountDisplayInfoFactory mAccountDisplayInfoFactory;
+ private AccountTypeManager mAccountTypeManager;
private int mChosenIndex = -1;
public DefaultAccountPreference(Context context) {
@@ -53,6 +55,7 @@
mPreferences = new ContactsPreferences(getContext());
mListAdapter = new AccountsListAdapter(getContext(),
AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE);
+ mAccountTypeManager = AccountTypeManager.getInstance(getContext());
mAccountDisplayInfoFactory = AccountDisplayInfoFactory.forWritableAccounts(getContext());
}
@@ -64,8 +67,12 @@
@Override
public CharSequence getSummary() {
final AccountWithDataSet defaultAccount = mPreferences.getDefaultAccount();
- return defaultAccount == null ? null : mAccountDisplayInfoFactory
- .getAccountDisplayInfo(defaultAccount).getNameLabel();
+ if (defaultAccount == null ||
+ !mAccountTypeManager.getAccounts(/* writable */ true).contains(defaultAccount)) {
+ return null;
+ } else {
+ return mAccountDisplayInfoFactory.getAccountDisplayInfo(defaultAccount).getNameLabel();
+ }
}
@Override
@@ -86,17 +93,12 @@
protected void onDialogClosed(boolean positiveResult) {
final AccountWithDataSet currentDefault = mPreferences.getDefaultAccount();
- if (mChosenIndex == -1) {
- if (currentDefault != null) {
- mPreferences.setDefaultAccount(null);
- notifyChanged();
- }
- } else {
+ if (mChosenIndex != -1) {
final AccountWithDataSet chosenAccount = mListAdapter.getItem(mChosenIndex);
if (!chosenAccount.equals(currentDefault)) {
mPreferences.setDefaultAccount(chosenAccount);
notifyChanged();
}
- }
+ } // else the user dismissed this dialog so leave the preference unchanged.
}
}
diff --git a/src/com/android/contacts/common/util/AccountFilterUtil.java b/src/com/android/contacts/common/util/AccountFilterUtil.java
index 78552c7..2e57c65 100644
--- a/src/com/android/contacts/common/util/AccountFilterUtil.java
+++ b/src/com/android/contacts/common/util/AccountFilterUtil.java
@@ -41,6 +41,7 @@
import com.android.contacts.common.model.RawContact;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contactsbind.ObjectFactory;
import com.google.common.collect.Lists;
@@ -160,20 +161,7 @@
}
private static AccountWithDataSet getDefaultAccount(Context context) {
- final SharedPreferences prefs =
- context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
- final String defaultAccountKey =
- context.getResources().getString(R.string.contact_editor_default_account_key);
- final String defaultAccountString = prefs.getString(defaultAccountKey, null);
- if (TextUtils.isEmpty(defaultAccountString)) {
- return null;
- }
- try {
- return AccountWithDataSet.unstringify(defaultAccountString);
- } catch (IllegalArgumentException exception) {
- Log.e(TAG, "Error with retrieving default account " + exception.toString(), exception);
- return null;
- }
+ return new ContactsPreferences(context).getDefaultAccount();
}
/**
diff --git a/src/com/android/contacts/editor/AccountsChangedBroadcastReceiver.java b/src/com/android/contacts/editor/AccountsChangedBroadcastReceiver.java
deleted file mode 100644
index 55300d5..0000000
--- a/src/com/android/contacts/editor/AccountsChangedBroadcastReceiver.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2016 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.contacts.editor;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.contacts.R;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-
-import java.util.List;
-
-/**
- * This class is to fix the bug that no prompt is seen for multiple accounts while creating new
- * contacts. By registering a BroadcastReceiver statically, we detect the changes of accounts by
- * receiving the message "android.accounts.LOGIN_ACCOUNTS_CHANGED". If the BroadcastReceiver gets
- * this message, it will get the default account from the SharedPreference and compare current
- * accounts with the default account. At last, it will renew the default account in the
- * SharedPreference if necessary.
- */
-public class AccountsChangedBroadcastReceiver extends BroadcastReceiver {
- final String TAG = "AccountsChanged";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Context appContext = context.getApplicationContext();
- final ContactEditorUtils contactEditorUtils = ContactEditorUtils.getInstance(appContext);
- final String defaultAccountKey = appContext.getResources().getString(
- R.string.contact_editor_default_account_key);
- final SharedPreferences pref = appContext.getSharedPreferences(
- appContext.getPackageName(), Context.MODE_PRIVATE);
- final String defaultAccountString = pref.getString(defaultAccountKey, null);
-
- if (!TextUtils.isEmpty(defaultAccountString)) {
- AccountWithDataSet defaultAccount;
- try {
- defaultAccount = AccountWithDataSet.unstringify(defaultAccountString);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Invalid string in SharedPreference", e);
- contactEditorUtils.saveDefaultAndAllAccounts(null);
- return;
- }
-
- final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(
- appContext);
- final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true);
- // Delete default account pref if it has been deleted.
- if (accounts == null || accounts.size() < 1 || !accounts.contains(defaultAccount)) {
- contactEditorUtils.saveDefaultAndAllAccounts(null);
- }
- }
- }
-}
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 0e7d6e6..4e7c3c5 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -489,7 +489,7 @@
public void onAttach(Activity activity) {
super.onAttach(activity);
mContext = activity;
- mEditorUtils = ContactEditorUtils.getInstance(mContext);
+ mEditorUtils = ContactEditorUtils.create(mContext);
mComparator = new RawContactDeltaComparator(mContext);
}
@@ -1113,7 +1113,7 @@
} else {
// Otherwise, there should be a default account. Then either create a local contact
// (if default account is null) or create a contact with the specified account.
- AccountWithDataSet defaultAccount = mEditorUtils.getDefaultAccount();
+ AccountWithDataSet defaultAccount = mEditorUtils.getOnlyOrDefaultAccount();
createContact(defaultAccount);
}
}
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index dd7d587..438618d 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -515,7 +515,7 @@
mIsUserProfile = isUserProfile;
mPrimaryAccount = primaryAccount;
if (mPrimaryAccount == null) {
- mPrimaryAccount = ContactEditorUtils.getInstance(getContext()).getDefaultAccount();
+ mPrimaryAccount = ContactEditorUtils.create(getContext()).getOnlyOrDefaultAccount();
}
vlog("state: primary " + mPrimaryAccount);
diff --git a/src/com/android/contacts/editor/ContactEditorUtils.java b/src/com/android/contacts/editor/ContactEditorUtils.java
index 24c6c26..fc1a887 100644
--- a/src/com/android/contacts/editor/ContactEditorUtils.java
+++ b/src/com/android/contacts/editor/ContactEditorUtils.java
@@ -22,18 +22,15 @@
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.net.Uri;
import android.provider.ContactsContract;
import android.text.TextUtils;
-import android.util.Log;
-import com.android.contacts.common.R;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.preference.ContactsPreferences;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -46,18 +43,8 @@
public class ContactEditorUtils {
private static final String TAG = "ContactEditorUtils";
- private static final String KEY_KNOWN_ACCOUNTS = "ContactEditorUtils_known_accounts";
-
- private static final List<AccountWithDataSet> EMPTY_ACCOUNTS = ImmutableList.of();
-
- private static ContactEditorUtils sInstance;
-
- private final Context mContext;
- private final SharedPreferences mPrefs;
+ private final ContactsPreferences mContactsPrefs;
private final AccountTypeManager mAccountTypes;
- private final String mDefaultAccountKey;
- // Key to tell the first time launch.
- private final String mAnythingSavedKey;
private ContactEditorUtils(Context context) {
this(context, AccountTypeManager.getInstance(context));
@@ -65,20 +52,12 @@
@VisibleForTesting
ContactEditorUtils(Context context, AccountTypeManager accountTypes) {
- mContext = context.getApplicationContext();
- mPrefs = mContext.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ mContactsPrefs = new ContactsPreferences(context);
mAccountTypes = accountTypes;
- mDefaultAccountKey = mContext.getResources().getString(
- R.string.contact_editor_default_account_key);
- mAnythingSavedKey = mContext.getResources().getString(
- R.string.contact_editor_anything_saved_key);
}
- public static synchronized ContactEditorUtils getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new ContactEditorUtils(context.getApplicationContext());
- }
- return sInstance;
+ public static ContactEditorUtils create(Context context) {
+ return new ContactEditorUtils(context.getApplicationContext());
}
/**
@@ -106,20 +85,11 @@
}
void cleanupForTest() {
- mPrefs.edit().remove(mDefaultAccountKey).remove(KEY_KNOWN_ACCOUNTS)
- .remove(mAnythingSavedKey).apply();
+ mContactsPrefs.clearDefaultAccount();
}
void removeDefaultAccountForTest() {
- mPrefs.edit().remove(mDefaultAccountKey).apply();
- }
-
- /**
- * Sets the {@link #KEY_KNOWN_ACCOUNTS} and {@link #mDefaultAccountKey} preference values to
- * empty strings to reset the state of the preferences file.
- */
- private void resetPreferenceValues() {
- mPrefs.edit().putString(KEY_KNOWN_ACCOUNTS, "").putString(mDefaultAccountKey, "").apply();
+ mContactsPrefs.clearDefaultAccount();
}
private List<AccountWithDataSet> getWritableAccounts() {
@@ -127,140 +97,39 @@
}
/**
- * @return true if it's the first launch and {@link #saveDefaultAndAllAccounts} has never
- * been called.
- */
- private boolean isFirstLaunch() {
- return !mPrefs.getBoolean(mAnythingSavedKey, false);
- }
-
- /**
- * Saves all writable accounts and the default account, which can later be obtained
- * with {@link #getDefaultAccount}.
+ * Saves the default account, which can later be obtained with {@link #getOnlyOrDefaultAccount}.
*
* This should be called when saving a newly created contact.
*
* @param defaultAccount the account used to save a newly created contact.
*/
- public void saveDefaultAndAllAccounts(AccountWithDataSet defaultAccount) {
- final SharedPreferences.Editor editor = mPrefs.edit()
- .putBoolean(mAnythingSavedKey, true);
-
+ public void saveDefaultAccount(AccountWithDataSet defaultAccount) {
if (defaultAccount == null) {
- editor.remove(KEY_KNOWN_ACCOUNTS);
- editor.remove(mDefaultAccountKey);
+ mContactsPrefs.clearDefaultAccount();
} else {
- editor.putString(KEY_KNOWN_ACCOUNTS,
- AccountWithDataSet.stringifyList(getWritableAccounts()));
- editor.putString(mDefaultAccountKey, defaultAccount.stringify());
+ mContactsPrefs.setDefaultAccount(defaultAccount);
}
- editor.apply();
}
/**
- * @return the default account saved with {@link #saveDefaultAndAllAccounts}.
+ * @return the first account if there is only a single account or the default account saved
+ * with {@link #saveDefaultAccount}.
*
- * Note the {@code null} return value can mean either {@link #saveDefaultAndAllAccounts} has
- * never been called, or {@code null} was passed to {@link #saveDefaultAndAllAccounts} --
- * i.e. the user selected "local only".
+ * A null return value indicates that there is multiple accounts and a default hasn't been set
*
* Also note that the returned account may have been removed already.
*/
- public AccountWithDataSet getDefaultAccount() {
+ public AccountWithDataSet getOnlyOrDefaultAccount() {
final List<AccountWithDataSet> currentWritableAccounts = getWritableAccounts();
if (currentWritableAccounts.size() == 1) {
return currentWritableAccounts.get(0);
}
- final String saved = mPrefs.getString(mDefaultAccountKey, null);
- if (TextUtils.isEmpty(saved)) {
- return null;
- }
- try {
- return AccountWithDataSet.unstringify(saved);
- } catch (IllegalArgumentException exception) {
- Log.e(TAG, "Error with retrieving default account " + exception.toString());
- // unstringify()can throw an exception if the string is not in an expected format.
- // Hence, if the preferences file is corrupt, just reset the preference values
- resetPreferenceValues();
- return null;
- }
+ return mContactsPrefs.getDefaultAccount();
}
- /**
- * @return true if an account still exists. {@code null} is considered "local only" here,
- * so it's valid too.
- */
- @VisibleForTesting
- boolean isValidAccount(AccountWithDataSet account) {
- if (account == null || account.isLocalAccount()) {
- return true; // It's "local only" account, which is valid.
- }
- return getWritableAccounts().contains(account);
- }
-
- /**
- * @return saved known accounts, or an empty list if none has been saved yet.
- */
- @VisibleForTesting
- List<AccountWithDataSet> getSavedAccounts() {
- final String saved = mPrefs.getString(KEY_KNOWN_ACCOUNTS, null);
- if (TextUtils.isEmpty(saved)) {
- return EMPTY_ACCOUNTS;
- }
- try {
- return AccountWithDataSet.unstringifyList(saved);
- } catch (IllegalArgumentException exception) {
- Log.e(TAG, "Error with retrieving saved accounts " + exception.toString());
- // unstringifyList()can throw an exception if the string is not in an expected format.
- // Hence, if the preferences file is corrupt, just reset the preference values
- resetPreferenceValues();
- return EMPTY_ACCOUNTS;
- }
- }
-
- /**
- * @return false if there is only one writable account or no requirement to return true is met.
- * true if the contact editor should show the "accounts changed" notification, that is:
- * - If it's the first launch.
- * - Or, if the default account has been removed.
- * (And some extra sanity check)
- *
- * Note if this method returns {@code false}, the caller can safely assume that
- * {@link #getDefaultAccount} will return a valid account. (Either an account which still
- * exists, or {@code null} which should be interpreted as "local only".)
- */
public boolean shouldShowAccountChangedNotification() {
- final List<AccountWithDataSet> currentWritableAccounts = getWritableAccounts();
-
- if (currentWritableAccounts.size() == 1) {
- // TODO: This will only work for devices that use a null device account but it should
- // probably should notify for other OEM device account types as well.
- return isFirstLaunch() && currentWritableAccounts.get(0).isLocalAccount();
- }
-
- if (isFirstLaunch()) {
- return true;
- }
-
- final AccountWithDataSet defaultAccount = getDefaultAccount();
-
- // Does default account still exist?
- if (!isValidAccount(defaultAccount)) {
- return true;
- }
-
- // If there is an inconsistent state in the preferences file then show the notification
- // dialog. This shouldn't ever happen, but this should allow the user can get back into a
- // normal state after they respond to the notification.
- if (defaultAccount == null) {
- Log.e(TAG, "Preferences file in an inconsistent state, request that the default account"
- + " and current writable accounts be saved again");
- return true;
- }
-
- // All good.
- return false;
+ return mContactsPrefs.shouldShowAccountChangedNotification(getWritableAccounts());
}
@VisibleForTesting
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 65be28a..4e53114 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -98,6 +98,11 @@
android:label="Contacts app tests">
</instrumentation>
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.contacts"
+ android:label="Contacts app tests">
+ </instrumentation>
+
<instrumentation android:name="com.android.contacts.ContactsLaunchPerformance"
android:targetPackage="com.android.contacts"
android:label="Contacts launch performance">
diff --git a/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java b/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java
index 7bfb922..9339063 100644
--- a/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java
+++ b/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java
@@ -59,11 +59,11 @@
}
public void testStringifyAndUnstringifyLocalAccount() {
- final String stringified = AccountWithDataSet.getLocalAccount().stringify();
+ final String stringified = AccountWithDataSet.getNullAccount().stringify();
final AccountWithDataSet restored = AccountWithDataSet.unstringify(stringified);
- assertEquals(AccountWithDataSet.getLocalAccount(), restored);
+ assertEquals(AccountWithDataSet.getNullAccount(), restored);
}
public void testStringifyListAndUnstringify() {
diff --git a/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java b/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java
index a841902..8400737 100644
--- a/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java
+++ b/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java
@@ -31,6 +31,8 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@SmallTest
public class ContactsPreferencesTest extends InstrumentationTestCase {
@@ -139,9 +141,8 @@
}
public void testRefreshDefaultAccount() throws InterruptedException {
- Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
- true // R.bool.config_default_account_user_changeable
- );
+ mContactsPreferences = new ContactsPreferences(mContext,
+ /* isDefaultAccountUserChangeable */ true);
Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
.thenReturn(new AccountWithDataSet("name1", "type1", "dataset1").stringify(),
@@ -154,4 +155,46 @@
Assert.assertEquals(new AccountWithDataSet("name2", "type2", "dataset2"),
mContactsPreferences.getDefaultAccount());
}
+
+ public void testShouldShowAccountChangedNotificationIfAccountNotSaved() {
+ mContactsPreferences = new ContactsPreferences(mContext,
+ /* isDefaultAccountUserChangeable */ true);
+ Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+ .thenReturn(null);
+
+ assertTrue("Should prompt to change default if no default is saved",
+ mContactsPreferences.shouldShowAccountChangedNotification(Arrays.asList(
+ new AccountWithDataSet("name1", "type1", "dataset1"),
+ new AccountWithDataSet("name2", "type2", "dataset2"))));
+ }
+
+ public void testShouldShowAccountChangedNotification() {
+ mContactsPreferences = new ContactsPreferences(mContext,
+ /* isDefaultAccountUserChangeable */ true);
+ Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+ .thenReturn(new AccountWithDataSet("name", "type", "dataset").stringify());
+
+ assertFalse("Should not prompt to change default if current default exists",
+ mContactsPreferences.shouldShowAccountChangedNotification(Arrays.asList(
+ new AccountWithDataSet("name", "type", "dataset"),
+ new AccountWithDataSet("name1", "type1", "dataset1"))));
+
+ assertTrue("Should prompt to change default if current default does not exist",
+ mContactsPreferences.shouldShowAccountChangedNotification(Arrays.asList(
+ new AccountWithDataSet("name1", "type1", "dataset1"),
+ new AccountWithDataSet("name2", "type2", "dataset2"))));
+ }
+
+ public void testShouldShowAccountChangedNotificationWhenThereIsOneAccount() {
+ mContactsPreferences = new ContactsPreferences(mContext,
+ /* isDefaultAccountUserChangeable */ true);
+ Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+ .thenReturn(null);
+
+ // Normally we would prompt because there is no default set but if there is just one
+ // account we should just use it.
+ assertFalse("Should not prompt to change default if there is only one account available",
+ mContactsPreferences.shouldShowAccountChangedNotification(Arrays.asList(
+ new AccountWithDataSet("name", "type", "dataset"))));
+ }
}
diff --git a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
index b5df8c9..525a85c 100644
--- a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
+++ b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
@@ -111,63 +111,18 @@
/**
* Test for
- * - {@link ContactEditorUtils#saveDefaultAndAllAccounts}
- * - {@link ContactEditorUtils#getDefaultAccount}
- * - {@link ContactEditorUtils#getSavedAccounts()}
+ * - {@link ContactEditorUtils#saveDefaultAccount}
+ * - {@link ContactEditorUtils#getOnlyOrDefaultAccount}
*/
- public void testSaveDefaultAndAllAccounts() {
+ public void testSaveDefaultAccount() {
// Use these account types here.
setAccountTypes(TYPE1, TYPE2);
- // If none has been saved, it should return an empty list.
- assertEquals(0, mTarget.getSavedAccounts().size());
+ mTarget.saveDefaultAccount(null);
+ assertNull(mTarget.getOnlyOrDefaultAccount());
- // Save 0 accounts.
- mAccountTypes.mAccounts = new AccountWithDataSet[]{};
- mTarget.saveDefaultAndAllAccounts(null);
- assertNull(mTarget.getDefaultAccount());
- MoreAsserts.assertEquals(
- Sets.newHashSet(mAccountTypes.mAccounts),
- toSet(mTarget.getSavedAccounts()));
-
- // 1 account
- mAccountTypes.mAccounts = new AccountWithDataSet[]{ACCOUNT_1_A};
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
- assertEquals(ACCOUNT_1_A, mTarget.getDefaultAccount());
- MoreAsserts.assertEquals(
- Sets.newHashSet(mAccountTypes.mAccounts),
- toSet(mTarget.getSavedAccounts()));
-
- // 2 accounts
- mAccountTypes.mAccounts = new AccountWithDataSet[]{ACCOUNT_1_A, ACCOUNT_1_B};
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_B);
- assertEquals(ACCOUNT_1_B, mTarget.getDefaultAccount());
- MoreAsserts.assertEquals(
- Sets.newHashSet(mAccountTypes.mAccounts),
- toSet(mTarget.getSavedAccounts()));
-
- // 2 accounts, and save null as the default. Even though there are accounts, the saved
- // account list should be empty in this case.
- mTarget.saveDefaultAndAllAccounts(null);
- assertNull(mTarget.getDefaultAccount());
- assertEquals(0, mTarget.getSavedAccounts().size());
- }
-
- public void testIsAccountValid() {
- // Use these account types here.
- setAccountTypes(TYPE1, TYPE2);
-
- // 0 accounts
- mAccountTypes.mAccounts = new AccountWithDataSet[]{};
- assertFalse(mTarget.isValidAccount(ACCOUNT_1_A));
- assertTrue(mTarget.isValidAccount(null)); // null is always valid
-
- // 2 accounts
- mAccountTypes.mAccounts = new AccountWithDataSet[]{ACCOUNT_1_A, ACCOUNT_2_A};
- assertTrue(mTarget.isValidAccount(ACCOUNT_1_A));
- assertTrue(mTarget.isValidAccount(ACCOUNT_2_A));
- assertFalse(mTarget.isValidAccount(ACCOUNT_2EX_A));
- assertTrue(mTarget.isValidAccount(null)); // null is always valid
+ mTarget.saveDefaultAccount(ACCOUNT_1_A);
+ assertEquals(ACCOUNT_1_A, mTarget.getOnlyOrDefaultAccount());
}
/**
@@ -186,7 +141,7 @@
// Now we open the contact editor with the new account.
// When closing the editor, we save the default account.
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
+ mTarget.saveDefaultAccount(ACCOUNT_1_A);
// Next time the user creates a contact, we don't show the notification.
assertFalse(mTarget.shouldShowAccountChangedNotification());
@@ -198,7 +153,7 @@
assertFalse(mTarget.shouldShowAccountChangedNotification());
// User saved a new contact. We update the account list and the default account.
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_B);
+ mTarget.saveDefaultAccount(ACCOUNT_1_B);
// User created another contact. Now we don't show the notification.
assertFalse(mTarget.shouldShowAccountChangedNotification());
@@ -214,7 +169,7 @@
assertFalse(mTarget.shouldShowAccountChangedNotification());
// User saves a new contact, with a different default account.
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_2_A);
+ mTarget.saveDefaultAccount(ACCOUNT_2_A);
// Next time user creates a contact, no notification.
assertFalse(mTarget.shouldShowAccountChangedNotification());
@@ -253,7 +208,7 @@
assertFalse(mTarget.shouldShowAccountChangedNotification());
// User saves a new contact.
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
+ mTarget.saveDefaultAccount(ACCOUNT_1_A);
// Next time, no notification.
assertFalse(mTarget.shouldShowAccountChangedNotification());
@@ -272,7 +227,7 @@
assertTrue(mTarget.shouldShowAccountChangedNotification());
// We show the notification here, and user clicked "keep local" and saved an contact.
- mTarget.saveDefaultAndAllAccounts(AccountWithDataSet.getLocalAccount());
+ mTarget.saveDefaultAccount(AccountWithDataSet.getNullAccount());
// Now there are no accounts, and default account is null.
@@ -285,7 +240,7 @@
setAccountTypes(TYPE1);
setAccounts(ACCOUNT_1_A);
- mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
+ mTarget.saveDefaultAccount(ACCOUNT_1_A);
// Right after a save, the dialog shouldn't show up.
assertFalse(mTarget.shouldShowAccountChangedNotification());
diff --git a/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java b/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java
index e68511f..aa3f725 100644
--- a/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java
+++ b/tests/src/com/android/contacts/editor/EditorUiUtilsTest.java
@@ -122,7 +122,7 @@
}
public void testGetAccountInfo_AccountType_DeviceAccount() {
- final AccountWithDataSet deviceAccount = AccountWithDataSet.getLocalAccount();
+ final AccountWithDataSet deviceAccount = AccountWithDataSet.getNullAccount();
final AccountDisplayInfo account = new AccountDisplayInfo(deviceAccount, "Device",
"Device", /*icon*/ null, /*isDeviceAccount*/ true);