From ffe54b4fd6c33f2b80b3375c02a9db391b0da140 Mon Sep 17 00:00:00 2001 From: Dongzhuo Zhang Date: Thu, 14 Nov 2024 00:45:08 +0000 Subject: [PATCH] Add OnAccountsUpdateListener in ContactsStorageSettings to refresh the account when there's account change. Test: atest SettingsRoboTests:com.android.settings.applications.contacts.ContactsStorageSettingsTest Bug: 368641291 Flag: com.android.settings.flags.enable_contacts_default_account_in_settings Change-Id: Ic51ac292d4321ddeb16a4ea1ee44ba02dcc6e02b --- .../contacts/ContactsStorageSettings.java | 38 +++++-- .../contacts/ContactsStorageSettingsTest.java | 105 +++++++++++++++--- 2 files changed, 120 insertions(+), 23 deletions(-) diff --git a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java index 5e48dd98ec6..4b70d465fb1 100644 --- a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java +++ b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java @@ -25,7 +25,6 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; import android.content.res.Resources; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState; @@ -58,7 +57,8 @@ import java.util.Map; */ @SearchIndexable public class ContactsStorageSettings extends DashboardFragment - implements SelectorWithWidgetPreference.OnClickListener, OnPreferenceClickListener { + implements SelectorWithWidgetPreference.OnClickListener, OnPreferenceClickListener, + AuthenticatorHelper.OnAccountsUpdateListener { public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.contacts_storage_settings); private static final String TAG = "ContactsStorageSettings"; @@ -72,13 +72,15 @@ public class ContactsStorageSettings extends DashboardFragment public void onAttach(@NonNull Context context) { super.onAttach(context); mAuthenticatorHelper = new AuthenticatorHelper(context, - new UserHandle(UserHandle.myUserId()), null); - String[] accountTypes = getEligibleAccountTypes(); - for (String accountType : accountTypes) { - // Preload the drawable for the account type to avoid the latency when rendering the - // account preference. - mAuthenticatorHelper.preloadDrawableForType(context, accountType); - } + new UserHandle(UserHandle.myUserId()), this); + mAuthenticatorHelper.listenToAccountUpdates(); + preloadEligibleAccountIcon(); + } + + @Override + public void onDetach() { + super.onDetach(); + mAuthenticatorHelper.stopListeningToAccountUpdates(); } @UiThread @@ -126,6 +128,12 @@ public class ContactsStorageSettings extends DashboardFragment return false; } + @Override + public void onAccountsUpdate(UserHandle userHandle) { + preloadEligibleAccountIcon(); + refreshUI(); + } + @Override public void onCreatePreferences(@NonNull Bundle savedInstanceState, @NonNull String rootKey) { @@ -139,6 +147,7 @@ public class ContactsStorageSettings extends DashboardFragment // when creating eligible account preferences. mAccountMap.clear(); final PreferenceGroup preferenceGroup = findPreference(PREF_KEY_ACCOUNT_CATEGORY); + preferenceGroup.removeAll(); // If the default account is SIM, we should show in the page, otherwise don't show. SelectorWithWidgetPreference simAccountPreference = buildSimAccountPreference(); if (simAccountPreference != null) { @@ -152,12 +161,21 @@ public class ContactsStorageSettings extends DashboardFragment // If there's no eligible account types, the "Add Account" preference should // not be shown to the users. if (getEligibleAccountTypes().length > 0) { - getPreferenceScreen().addPreference(buildAddAccountPreference(accounts.isEmpty())); + preferenceGroup.addPreference(buildAddAccountPreference(accounts.isEmpty())); } setupDeviceOnlyPreference(); setDefaultAccountPreference(preferenceGroup); } + private void preloadEligibleAccountIcon() { + String[] accountTypes = getEligibleAccountTypes(); + for (String accountType : accountTypes) { + // Preload the drawable for the account type to avoid the latency when rendering the + // account preference. + mAuthenticatorHelper.preloadDrawableForType(getContext(), accountType); + } + } + private void setupDeviceOnlyPreference() { SelectorWithWidgetPreference preference = findPreference(PREF_KEY_DEVICE_ONLY); if (preference != null) { diff --git a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java index a2debd24ee2..735508ab9f8 100644 --- a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java +++ b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java @@ -38,10 +38,13 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.UserHandle; import android.provider.ContactsContract; import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState; import android.provider.SearchIndexableResource; +import android.text.TextUtils; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; @@ -51,7 +54,7 @@ import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.accounts.AddAccountSettings; -import com.android.settings.testutils.shadow.ShadowAuthenticationHelper; +import com.android.settingslib.accounts.AuthenticatorHelper; import com.android.settingslib.widget.SelectorWithWidgetPreference; import org.junit.Before; @@ -66,22 +69,24 @@ import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; import java.util.ArrayList; import java.util.List; @RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowAuthenticationHelper.class) +@Config(shadows = ContactsStorageSettingsTest.ShadowAuthenticatorHelper.class) public class ContactsStorageSettingsTest { private static final String PREF_KEY_DEVICE_ONLY = "device_only_account_preference"; private static final String PREF_KEY_ACCOUNT_CATEGORY = "account_category"; private static final String PREF_KEY_ADD_ACCOUNT = "add_account"; - private static final Account TEST_ACCOUNT1 = new Account("test@gmail.com", "type1"); + private static final Account TEST_ACCOUNT1 = new Account("test@gmail.com", "com.google"); - private static final Account TEST_ACCOUNT2 = new Account("test@samsung.com", "type2"); + private static final Account TEST_ACCOUNT2 = new Account("test@samsung.com", "com.samsung"); - private static final Account TEST_ACCOUNT3 = new Account("test@outlook.com", "type3"); + private static final Account TEST_ACCOUNT3 = new Account("test@outlook.com", "com.outlook"); private static final Account SIM_ACCOUNT = new Account("SIM", "SIM"); @@ -100,7 +105,8 @@ public class ContactsStorageSettingsTest { @Before public void setUp() throws Exception { - mContactsStorageSettings = spy(new TestContactsStorageSettings(mContext, mContentResolver)); + mContactsStorageSettings = spy( + new TestContactsStorageSettings(mContext, mContentResolver)); when(mContentResolver.acquireContentProviderClient( eq(ContactsContract.AUTHORITY_URI))).thenReturn(mContentProviderClient); mPreferenceManager = new PreferenceManager(mContext); @@ -116,6 +122,7 @@ public class ContactsStorageSettingsTest { when(mContactsStorageSettings.findPreference(eq(PREF_KEY_ACCOUNT_CATEGORY))).thenReturn( accountCategory); when(mContactsStorageSettings.getPreferenceScreen()).thenReturn(mScreen); + mContactsStorageSettings.setEligibleAccountTypes(new String[]{"com.google"}); mContactsStorageSettings.onAttach(mContext); } @@ -179,7 +186,6 @@ public class ContactsStorageSettingsTest { new ArrayList<>()); when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(), any())).thenReturn(eligibleAccountBundle); - mContactsStorageSettings.setEligibleAccountTypes(new String[]{"com.google"}); mContactsStorageSettings.refreshUI(); @@ -244,13 +250,13 @@ public class ContactsStorageSettingsTest { SelectorWithWidgetPreference account1Preference = accountCategory.findPreference( String.valueOf(TEST_ACCOUNT1.hashCode())); - assertThat(account1Preference.getTitle()).isEqualTo("Device and LABEL1"); + assertThat(account1Preference.getTitle()).isEqualTo("Device and Google"); assertThat(account1Preference.getSummary()).isEqualTo("test@gmail.com"); assertThat(account1Preference.getIcon()).isNotNull(); SelectorWithWidgetPreference account2Preference = accountCategory.findPreference( String.valueOf(TEST_ACCOUNT2.hashCode())); - assertThat(account2Preference.getTitle()).isEqualTo("Device and LABEL2"); + assertThat(account2Preference.getTitle()).isEqualTo("Device and Samsung"); assertThat(account2Preference.getSummary()).isEqualTo("test@samsung.com"); assertThat(account2Preference.getIcon()).isNotNull(); @@ -265,7 +271,7 @@ public class ContactsStorageSettingsTest { assertThat(setAccountBundle.getString(ContactsContract.Settings.ACCOUNT_NAME)).isEqualTo( "test@samsung.com"); assertThat(setAccountBundle.getString(ContactsContract.Settings.ACCOUNT_TYPE)).isEqualTo( - "type2"); + "com.samsung"); ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).startActivity(intentCaptor.capture()); @@ -298,19 +304,19 @@ public class ContactsStorageSettingsTest { SelectorWithWidgetPreference account1Preference = accountCategory.findPreference( String.valueOf(TEST_ACCOUNT1.hashCode())); - assertThat(account1Preference.getTitle()).isEqualTo("Device and LABEL1"); + assertThat(account1Preference.getTitle()).isEqualTo("Device and Google"); assertThat(account1Preference.getSummary()).isEqualTo("test@gmail.com"); assertThat(account1Preference.getIcon()).isNotNull(); SelectorWithWidgetPreference account2Preference = accountCategory.findPreference( String.valueOf(TEST_ACCOUNT2.hashCode())); - assertThat(account2Preference.getTitle()).isEqualTo("Device and LABEL2"); + assertThat(account2Preference.getTitle()).isEqualTo("Device and Samsung"); assertThat(account2Preference.getSummary()).isEqualTo("test@samsung.com"); assertThat(account2Preference.getIcon()).isNotNull(); SelectorWithWidgetPreference account3Preference = accountCategory.findPreference( String.valueOf(TEST_ACCOUNT3.hashCode())); - assertThat(account3Preference.getTitle()).isEqualTo("Device and LABEL3"); + assertThat(account3Preference.getTitle()).isEqualTo("Device and Outlook"); assertThat(account3Preference.getSummary()).isEqualTo("test@outlook.com"); assertThat(account3Preference.getIcon()).isNotNull(); @@ -345,6 +351,40 @@ public class ContactsStorageSettingsTest { assertThat(simPreference.isChecked()).isTrue(); } + @Test + public void verifyAccountPreference_newAccountAdded_accountAddedToAccountPreference() + throws Exception { + Bundle currentDefaultAccount = new Bundle(); + currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE, + DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD); + currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_NAME, TEST_ACCOUNT1.name); + currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_TYPE, TEST_ACCOUNT1.type); + when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(), + any())).thenReturn(currentDefaultAccount); + Bundle eligibleAccountBundle = new Bundle(); + ArrayList eligibleAccounts = new ArrayList<>( + List.of(TEST_ACCOUNT1, TEST_ACCOUNT2)); + eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS, + eligibleAccounts); + when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(), + any())).thenReturn(eligibleAccountBundle); + + mContactsStorageSettings.onAccountsUpdate(null); + + // onAccountsUpdate should refresh the icon and layouts. + SelectorWithWidgetPreference account1Preference = accountCategory.findPreference( + String.valueOf(TEST_ACCOUNT1.hashCode())); + assertThat(account1Preference.getTitle()).isEqualTo("Device and Google"); + assertThat(account1Preference.getSummary()).isEqualTo("test@gmail.com"); + assertThat(account1Preference.getIcon()).isNotNull(); + + SelectorWithWidgetPreference account2Preference = accountCategory.findPreference( + String.valueOf(TEST_ACCOUNT2.hashCode())); + assertThat(account2Preference.getTitle()).isEqualTo("Device and Samsung"); + assertThat(account2Preference.getSummary()).isEqualTo("test@samsung.com"); + assertThat(account2Preference.getIcon()).isNotNull(); + } + @Test public void searchIndexProvider_shouldIndexResource() { final List indexRes = @@ -388,4 +428,43 @@ public class ContactsStorageSettingsTest { mEligibleAccountTypes = eligibleAccountTypes; } } + + @Implements(AuthenticatorHelper.class) + public static class ShadowAuthenticatorHelper { + + boolean preloadDrawableForType = false; + + @Implementation + public void listenToAccountUpdates() { + } + + @Implementation + public void onAccountsUpdated(Account[] accounts) { + + } + @Implementation + public void preloadDrawableForType(final Context context, final String accountType) { + preloadDrawableForType = true; + } + + @Implementation + protected Drawable getDrawableForType(Context context, final String accountType) { + if (preloadDrawableForType) { + return context.getPackageManager().getDefaultActivityIcon(); + } + return null; + } + + @Implementation + protected CharSequence getLabelForType(Context context, final String accountType) { + if (TextUtils.equals(accountType, "com.google")) { + return "Google"; + } else if (TextUtils.equals(accountType, "com.samsung")) { + return "Samsung"; + } else if (TextUtils.equals(accountType, "com.outlook")) { + return "Outlook"; + } + return null; + } + } }