Use ListFormatter to join strings

Currently in Settings we are using R.string.join_many_items_first, R.string.join_many_items_middle and R.string.join_many_items_last to manually join strings. The join code is messy and the joined string is incorrect in some languages, so we migrate all string join to just use ListFormatter.getInstance().format().

Bug: b/78248791
Test: robotests
Change-Id: I898339978e6e2027587e28994b0280fa46821fd6
This commit is contained in:
jyhshiangwang
2018-04-24 16:05:57 +08:00
parent 7c45f59478
commit 4d015b17b3
12 changed files with 210 additions and 212 deletions

View File

@@ -4048,12 +4048,6 @@
<string name="join_two_items"><xliff:g id="first_item">%1$s</xliff:g> and <xliff:g id="second_item">%2$s</xliff:g></string> <string name="join_two_items"><xliff:g id="first_item">%1$s</xliff:g> and <xliff:g id="second_item">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=NONE] Format to put together two unrelated items in a list when "and" is not an appropriate conjunction for these 2 items --> <!-- [CHAR_LIMIT=NONE] Format to put together two unrelated items in a list when "and" is not an appropriate conjunction for these 2 items -->
<string name="join_two_unrelated_items"><xliff:g id="first_item">%1$s</xliff:g>, <xliff:g id="second_item">%2$s</xliff:g></string> <string name="join_two_unrelated_items"><xliff:g id="first_item">%1$s</xliff:g>, <xliff:g id="second_item">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=NONE] Format to put the last item at the end of a series of 3 or more items in a list -->
<string name="join_many_items_last"><xliff:g id="all_but_last_item">%1$s</xliff:g>, and <xliff:g id="last_item">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=NONE] Format to put the first item at the start of a series of 3 or more items in a list -->
<string name="join_many_items_first"><xliff:g id="first_item">%1$s</xliff:g>, <xliff:g id="all_but_first_and_last_item">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=NONE] Format to put the middle items together in a series of 4 or more items in a list -->
<string name="join_many_items_middle"><xliff:g id="added_item">%1$s</xliff:g>, <xliff:g id="rest_of_items">%2$s</xliff:g></string>
<!-- Manage applications, individual application info screen, text that appears under the "Permissions" heading after the app has tried to send to a premium SMS. [CHAR LIMIT=50] --> <!-- Manage applications, individual application info screen, text that appears under the "Permissions" heading after the app has tried to send to a premium SMS. [CHAR LIMIT=50] -->
<string name="security_settings_billing_desc">This app may charge you money:</string> <string name="security_settings_billing_desc">This app may charge you money:</string>
<!-- Manage applications, text for permission to send to premium SMS short codes. [CHAR LIMIT=40] --> <!-- Manage applications, text for permission to send to premium SMS short codes. [CHAR LIMIT=40] -->

View File

@@ -19,6 +19,7 @@ import static android.provider.Settings.EXTRA_AUTHORITIES;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.icu.text.ListFormatter;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.text.BidiFormatter; import android.text.BidiFormatter;
@@ -96,12 +97,11 @@ public class AccountDashboardFragment extends DashboardFragment {
final AuthenticatorHelper authHelper = new AuthenticatorHelper(mContext, final AuthenticatorHelper authHelper = new AuthenticatorHelper(mContext,
UserHandle.of(UserHandle.myUserId()), null /* OnAccountsUpdateListener */); UserHandle.of(UserHandle.myUserId()), null /* OnAccountsUpdateListener */);
final String[] types = authHelper.getEnabledAccountTypes(); final String[] types = authHelper.getEnabledAccountTypes();
final BidiFormatter bidiFormatter = BidiFormatter.getInstance(); final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
final List<CharSequence> summaries = new ArrayList<>();
CharSequence summary = null;
if (types == null || types.length == 0) { if (types == null || types.length == 0) {
summary = mContext.getString(R.string.account_dashboard_default_summary); summaries.add(mContext.getString(R.string.account_dashboard_default_summary));
} else { } else {
// Show up to 3 account types, ignore any null value // Show up to 3 account types, ignore any null value
int accountToAdd = Math.min(3, types.length); int accountToAdd = Math.min(3, types.length);
@@ -111,16 +111,12 @@ public class AccountDashboardFragment extends DashboardFragment {
if (TextUtils.isEmpty(label)) { if (TextUtils.isEmpty(label)) {
continue; continue;
} }
if (summary == null) {
summary = bidiFormatter.unicodeWrap(label); summaries.add(bidiFormatter.unicodeWrap(label));
} else {
summary = mContext.getString(R.string.join_many_items_middle, summary,
bidiFormatter.unicodeWrap(label));
}
accountToAdd--; accountToAdd--;
} }
} }
mSummaryLoader.setSummary(this, summary); mSummaryLoader.setSummary(this, ListFormatter.getInstance().format(summaries));
} }
} }
} }

View File

@@ -19,13 +19,14 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo; import android.content.pm.PermissionInfo;
import android.text.TextUtils; import android.icu.text.ListFormatter;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -33,7 +34,7 @@ public class AppPermissionsPreferenceController extends BasePreferenceController
private static final String TAG = "AppPermissionPrefCtrl"; private static final String TAG = "AppPermissionPrefCtrl";
private static final String KEY_APP_PERMISSION_GROUPS = "manage_perms"; private static final String KEY_APP_PERMISSION_GROUPS = "manage_perms";
private static final String[] PERMISSION_GROUPS = new String[] { private static final String[] PERMISSION_GROUPS = new String[]{
"android.permission-group.LOCATION", "android.permission-group.LOCATION",
"android.permission-group.MICROPHONE", "android.permission-group.MICROPHONE",
"android.permission-group.CAMERA", "android.permission-group.CAMERA",
@@ -64,18 +65,20 @@ public class AppPermissionsPreferenceController extends BasePreferenceController
public CharSequence getSummary() { public CharSequence getSummary() {
final Set<String> permissions = getAllPermissionsInGroups(); final Set<String> permissions = getAllPermissionsInGroups();
Set<String> grantedPermissionGroups = getGrantedPermissionGroups(permissions); Set<String> grantedPermissionGroups = getGrantedPermissionGroups(permissions);
CharSequence summary = null;
int count = 0; int count = 0;
final List<String> summaries = new ArrayList<>();
for (String group : PERMISSION_GROUPS) { for (String group : PERMISSION_GROUPS) {
if (!grantedPermissionGroups.contains(group)) { if (!grantedPermissionGroups.contains(group)) {
continue; continue;
} }
summary = concatSummaryText(summary, group); summaries.add(getPermissionGroupLabel(group).toString().toLowerCase());
if (++count >= NUM_PERMISSION_TO_USE) { if (++count >= NUM_PERMISSION_TO_USE) {
break; break;
} }
} }
return count > 0 ? mContext.getString(R.string.app_permissions_summary, summary) : null; return count > 0 ? mContext.getString(R.string.app_permissions_summary,
ListFormatter.getInstance().format(summaries)) : null;
} }
private Set<String> getGrantedPermissionGroups(Set<String> permissions) { private Set<String> getGrantedPermissionGroups(Set<String> permissions) {
@@ -96,14 +99,6 @@ public class AppPermissionsPreferenceController extends BasePreferenceController
return grantedPermissionGroups; return grantedPermissionGroups;
} }
private CharSequence concatSummaryText(CharSequence currentSummary, String permission) {
final String label = getPermissionGroupLabel(permission).toString().toLowerCase();
if (TextUtils.isEmpty(currentSummary)) {
return label;
}
return mContext.getString(R.string.join_many_items_middle, currentSummary, label);
}
private CharSequence getPermissionGroupLabel(String group) { private CharSequence getPermissionGroupLabel(String group) {
try { try {
final PermissionGroupInfo groupInfo = mPackageManager.getPermissionGroupInfo(group, 0); final PermissionGroupInfo groupInfo = mPackageManager.getPermissionGroupInfo(group, 0);

View File

@@ -17,6 +17,7 @@ package com.android.settings.applications;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.icu.text.ListFormatter;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.text.TextUtils; import android.text.TextUtils;
@@ -138,25 +139,22 @@ public class DefaultAppSettings extends DashboardFragment {
if (!listening) { if (!listening) {
return; return;
} }
CharSequence summary = concatSummaryText( final List<CharSequence> summaries = new ArrayList<>();
mDefaultBrowserPreferenceController.getDefaultAppLabel(), if(!TextUtils.isEmpty(mDefaultBrowserPreferenceController.getDefaultAppLabel())) {
mDefaultPhonePreferenceController.getDefaultAppLabel()); summaries.add(mDefaultBrowserPreferenceController.getDefaultAppLabel());
summary = concatSummaryText(summary, }
mDefaultSmsPreferenceController.getDefaultAppLabel()); if(!TextUtils.isEmpty(mDefaultPhonePreferenceController.getDefaultAppLabel())) {
summaries.add(mDefaultPhonePreferenceController.getDefaultAppLabel());
}
if(!TextUtils.isEmpty(mDefaultSmsPreferenceController.getDefaultAppLabel())) {
summaries.add(mDefaultSmsPreferenceController.getDefaultAppLabel());
}
CharSequence summary = ListFormatter.getInstance().format(summaries);
if (!TextUtils.isEmpty(summary)) { if (!TextUtils.isEmpty(summary)) {
mSummaryLoader.setSummary(this, summary); mSummaryLoader.setSummary(this, summary);
} }
} }
private CharSequence concatSummaryText(CharSequence summary1, CharSequence summary2) {
if (TextUtils.isEmpty(summary1)) {
return summary2;
}
if (TextUtils.isEmpty(summary2)) {
return summary1;
}
return mContext.getString(R.string.join_many_items_middle, summary1, summary2);
}
} }
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY = public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY =

View File

@@ -18,6 +18,9 @@ package com.android.settings.inputmethod;
import android.content.Context; import android.content.Context;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.icu.text.ListFormatter;
import androidx.preference.Preference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
@@ -28,9 +31,9 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.core.lifecycle.events.OnResume;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.preference.Preference;
public class PhysicalKeyboardPreferenceController extends AbstractPreferenceController public class PhysicalKeyboardPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause, implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause,
@@ -100,15 +103,10 @@ public class PhysicalKeyboardPreferenceController extends AbstractPreferenceCont
mPreference.setSummary(R.string.keyboard_disconnected); mPreference.setSummary(R.string.keyboard_disconnected);
return; return;
} }
String summary = null; final List<String> summaries = new ArrayList<>();
for (HardKeyboardDeviceInfo info : keyboards) { for (HardKeyboardDeviceInfo info : keyboards) {
if (summary == null) { summaries.add(info.mDeviceName);
summary = info.mDeviceName;
} else {
summary = mContext.getString(R.string.join_many_items_middle, summary,
info.mDeviceName);
}
} }
mPreference.setSummary(summary); mPreference.setSummary(ListFormatter.getInstance().format(summaries));
} }
} }

View File

@@ -19,11 +19,13 @@ package com.android.settings.inputmethod;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import androidx.preference.Preference; import android.icu.text.ListFormatter;
import android.text.BidiFormatter; import android.text.BidiFormatter;
import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import androidx.preference.Preference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
@@ -81,15 +83,10 @@ public class VirtualKeyboardPreferenceController extends AbstractPreferenceContr
final BidiFormatter bidiFormatter = BidiFormatter.getInstance(); final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
String summary = null; final List<String> summaries = new ArrayList<>();
for (String label : labels) { for (String label : labels) {
if (summary == null) { summaries.add(bidiFormatter.unicodeWrap(label));
summary = bidiFormatter.unicodeWrap(label);
} else {
summary = mContext.getString(R.string.join_many_items_middle, summary,
bidiFormatter.unicodeWrap(label));
}
} }
preference.setSummary(summary); preference.setSummary(ListFormatter.getInstance().format(summaries));
} }
} }

View File

@@ -21,9 +21,11 @@ import android.app.FragmentManager;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.NotificationManager.Policy; import android.app.NotificationManager.Policy;
import android.content.Context; import android.content.Context;
import android.icu.text.ListFormatter;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.provider.Settings; import android.provider.Settings;
import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.CheckBoxPreference; import androidx.preference.CheckBoxPreference;
@@ -44,6 +46,7 @@ import java.util.Map.Entry;
@SearchIndexable @SearchIndexable
public class ZenModeSettings extends ZenModeSettingsBase { public class ZenModeSettings extends ZenModeSettingsBase {
private static final String KEY_SOUND = "zen_effect_sound"; private static final String KEY_SOUND = "zen_effect_sound";
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@@ -118,18 +121,21 @@ public class ZenModeSettings extends ZenModeSettingsBase {
} else if (numCategories == 2) { } else if (numCategories == 2) {
return mContext.getString(R.string.join_two_items, enabledCategories.get(0), return mContext.getString(R.string.join_two_items, enabledCategories.get(0),
enabledCategories.get(1).toLowerCase()); enabledCategories.get(1).toLowerCase());
} else if (numCategories == 3){ } else if (numCategories == 3) {
String secondaryText = mContext.getString(R.string.join_two_unrelated_items, final List<String> summaries = new ArrayList<>();
enabledCategories.get(0), enabledCategories.get(1).toLowerCase()); summaries.add(enabledCategories.get(0));
return mContext.getString(R.string.join_many_items_last, secondaryText, summaries.add(enabledCategories.get(1).toLowerCase());
enabledCategories.get(2).toLowerCase()); summaries.add(enabledCategories.get(2).toLowerCase());
return ListFormatter.getInstance().format(summaries);
} else { } else {
String secondaryText = mContext.getString(R.string.join_many_items_middle, final List<String> summaries = new ArrayList<>();
enabledCategories.get(0), enabledCategories.get(1).toLowerCase()); summaries.add(enabledCategories.get(0));
secondaryText = mContext.getString(R.string.join_many_items_middle, secondaryText, summaries.add(enabledCategories.get(1).toLowerCase());
enabledCategories.get(2).toLowerCase()); summaries.add(enabledCategories.get(2).toLowerCase());
return mContext.getString(R.string.join_many_items_last, secondaryText, summaries.add(mContext.getString(R.string.zen_mode_other_options));
mContext.getString(R.string.zen_mode_other_options));
return ListFormatter.getInstance().format(summaries);
} }
} }
@@ -175,15 +181,15 @@ public class ZenModeSettings extends ZenModeSettingsBase {
String getAutomaticRulesSummary() { String getAutomaticRulesSummary() {
final int count = getEnabledAutomaticRulesCount(); final int count = getEnabledAutomaticRulesCount();
return count == 0 ? mContext.getString(R.string.zen_mode_settings_summary_off) return count == 0 ? mContext.getString(R.string.zen_mode_settings_summary_off)
: mContext.getResources().getQuantityString( : mContext.getResources().getQuantityString(
R.plurals.zen_mode_settings_summary_on, count, count); R.plurals.zen_mode_settings_summary_on, count, count);
} }
@VisibleForTesting @VisibleForTesting
int getEnabledAutomaticRulesCount() { int getEnabledAutomaticRulesCount() {
int count = 0; int count = 0;
final Map<String, AutomaticZenRule> ruleMap = final Map<String, AutomaticZenRule> ruleMap =
NotificationManager.from(mContext).getAutomaticZenRules(); NotificationManager.from(mContext).getAutomaticZenRules();
if (ruleMap != null) { if (ruleMap != null) {
for (Entry<String, AutomaticZenRule> ruleEntry : ruleMap.entrySet()) { for (Entry<String, AutomaticZenRule> ruleEntry : ruleMap.entrySet()) {
final AutomaticZenRule rule = ruleEntry.getValue(); final AutomaticZenRule rule = ruleEntry.getValue();

View File

@@ -25,7 +25,6 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffColorFilter;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.icu.text.DecimalFormatSymbols; import android.icu.text.DecimalFormatSymbols;
import androidx.annotation.ColorRes;
import android.text.Layout; import android.text.Layout;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
@@ -37,6 +36,8 @@ import android.text.style.RelativeSizeSpan;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import androidx.annotation.ColorRes;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
@@ -207,7 +208,7 @@ public class DonutView extends View {
R.dimen.storage_donut_view_shrunken_label_text_size)); R.dimen.storage_donut_view_shrunken_label_text_size));
} }
setContentDescription(getContext().getString( setContentDescription(getContext().getString(
R.string.join_many_items_middle, mPercentString, mFullString)); R.string.join_two_unrelated_items, mPercentString, mFullString));
invalidate(); invalidate();
} }

View File

@@ -15,9 +15,13 @@
*/ */
package com.android.settings.accounts; package com.android.settings.accounts;
import static com.android.settings.accounts.AccountDashboardFragmentTest.ShadowAuthenticationHelper.LABELS; import static com.android.settings.accounts.AccountDashboardFragmentTest
import static com.android.settings.accounts.AccountDashboardFragmentTest.ShadowAuthenticationHelper.TYPES; .ShadowAuthenticationHelper.LABELS;
import static com.android.settings.accounts.AccountDashboardFragmentTest
.ShadowAuthenticationHelper.TYPES;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -49,116 +53,119 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class AccountDashboardFragmentTest { public class AccountDashboardFragmentTest {
private AccountDashboardFragment mFragment; private AccountDashboardFragment mFragment;
@Before @Before
public void setUp() { public void setUp() {
mFragment = new AccountDashboardFragment(); mFragment = new AccountDashboardFragment();
}
@After
public void tearDown() {
ShadowAuthenticationHelper.reset();
}
@Test
public void testCategory_isAccount() {
assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
}
@Test
@Config(shadows = {
ShadowAuthenticationHelper.class
})
public void updateSummary_hasAccount_shouldDisplayUpTo3AccountTypes() {
final SummaryLoader loader = mock(SummaryLoader.class);
final Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity, loader);
provider.setListening(true);
verify(loader).setSummary(provider, LABELS[0] + ", " + LABELS[1] + ", " + LABELS[2]);
}
@Test
@Config(shadows = ShadowAuthenticationHelper.class)
public void updateSummary_noAccount_shouldDisplayDefaultSummary() {
ShadowAuthenticationHelper.setEnabledAccount(null);
final SummaryLoader loader = mock(SummaryLoader.class);
final Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity, loader);
provider.setListening(true);
verify(loader).setSummary(provider,
activity.getString(R.string.account_dashboard_default_summary));
}
@Test
@Config(shadows = ShadowAuthenticationHelper.class)
public void updateSummary_noAccountTypeLabel_shouldNotDisplayNullEntry() {
final SummaryLoader loader = mock(SummaryLoader.class);
final Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
final String[] enabledAccounts = {TYPES[0], "unlabeled_account_type", TYPES[1]};
ShadowAuthenticationHelper.setEnabledAccount(enabledAccounts);
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity, loader);
provider.setListening(true);
// should only show the 2 accounts with labels
verify(loader).setSummary(provider, LABELS[0] + ", " + LABELS[1]);
}
@Test
public void testSearchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =
AccountDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getXmlResourcesToIndex(RuntimeEnvironment.application, true /* enabled */);
assertThat(indexRes).isNotNull();
assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
}
@Implements(AuthenticatorHelper.class)
public static class ShadowAuthenticationHelper {
static final String[] TYPES = {"type1", "type2", "type3", "type4"};
static final String[] LABELS = {"LABEL1", "LABEL2", "LABEL3", "LABEL4"};
private static String[] sEnabledAccount = TYPES;
public void __constructor__(Context context, UserHandle userHandle,
AuthenticatorHelper.OnAccountsUpdateListener listener) {
} }
private static void setEnabledAccount(String[] enabledAccount) { @After
sEnabledAccount = enabledAccount; public void tearDown() {
ShadowAuthenticationHelper.reset();
} }
@Resetter @Test
public static void reset() { public void testCategory_isAccount() {
sEnabledAccount = TYPES; assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
} }
@Implementation @Test
public String[] getEnabledAccountTypes() { @Config(shadows = {
return sEnabledAccount; ShadowAuthenticationHelper.class
})
public void updateSummary_hasAccount_shouldDisplayUpTo3AccountTypes() {
final SummaryLoader loader = mock(SummaryLoader.class);
final Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity,
loader);
provider.setListening(true);
verify(loader).setSummary(provider, LABELS[0] + ", " + LABELS[1] + ", and " + LABELS[2]);
} }
@Implementation @Test
public CharSequence getLabelForType(Context context, final String accountType) { @Config(shadows = ShadowAuthenticationHelper.class)
if (TextUtils.equals(accountType, TYPES[0])) { public void updateSummary_noAccount_shouldDisplayDefaultSummary() {
return LABELS[0]; ShadowAuthenticationHelper.setEnabledAccount(null);
} else if (TextUtils.equals(accountType, TYPES[1])) { final SummaryLoader loader = mock(SummaryLoader.class);
return LABELS[1]; final Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
} else if (TextUtils.equals(accountType, TYPES[2])) {
return LABELS[2]; final SummaryLoader.SummaryProvider provider =
} else if (TextUtils.equals(accountType, TYPES[3])) { AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity,
return LABELS[3]; loader);
} provider.setListening(true);
return null;
verify(loader).setSummary(provider,
activity.getString(R.string.account_dashboard_default_summary));
}
@Test
@Config(shadows = ShadowAuthenticationHelper.class)
public void updateSummary_noAccountTypeLabel_shouldNotDisplayNullEntry() {
final SummaryLoader loader = mock(SummaryLoader.class);
final Activity activity = Robolectric.buildActivity(Activity.class).setup().get();
final String[] enabledAccounts = {TYPES[0], "unlabeled_account_type", TYPES[1]};
ShadowAuthenticationHelper.setEnabledAccount(enabledAccounts);
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity,
loader);
provider.setListening(true);
// should only show the 2 accounts with labels
verify(loader).setSummary(provider, LABELS[0] + " and " + LABELS[1]);
}
@Test
public void testSearchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =
AccountDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getXmlResourcesToIndex(RuntimeEnvironment.application, true /* enabled */);
assertThat(indexRes).isNotNull();
assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
}
@Implements(AuthenticatorHelper.class)
public static class ShadowAuthenticationHelper {
static final String[] TYPES = {"type1", "type2", "type3", "type4"};
static final String[] LABELS = {"LABEL1", "LABEL2", "LABEL3", "LABEL4"};
private static String[] sEnabledAccount = TYPES;
public void __constructor__(Context context, UserHandle userHandle,
AuthenticatorHelper.OnAccountsUpdateListener listener) {
}
private static void setEnabledAccount(String[] enabledAccount) {
sEnabledAccount = enabledAccount;
}
@Resetter
public static void reset() {
sEnabledAccount = TYPES;
}
@Implementation
public String[] getEnabledAccountTypes() {
return sEnabledAccount;
}
@Implementation
public CharSequence getLabelForType(Context context, final String accountType) {
if (TextUtils.equals(accountType, TYPES[0])) {
return LABELS[0];
} else if (TextUtils.equals(accountType, TYPES[1])) {
return LABELS[1];
} else if (TextUtils.equals(accountType, TYPES[2])) {
return LABELS[2];
} else if (TextUtils.equals(accountType, TYPES[3])) {
return LABELS[3];
}
return null;
}
} }
}
} }

View File

@@ -17,6 +17,7 @@
package com.android.settings.applications; package com.android.settings.applications;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
@@ -31,6 +32,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo; import android.content.pm.PermissionInfo;
import androidx.preference.Preference; import androidx.preference.Preference;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -95,21 +97,21 @@ public class AppPermissionsPreferenceControllerTest {
// create permission groups // create permission groups
when(mPackageManager.getPermissionGroupInfo(eq(PERM_LOCATION), anyInt())) when(mPackageManager.getPermissionGroupInfo(eq(PERM_LOCATION), anyInt()))
.thenReturn(mGroupLocation); .thenReturn(mGroupLocation);
when(mGroupLocation.loadLabel(mPackageManager)).thenReturn(LABEL_LOCATION); when(mGroupLocation.loadLabel(mPackageManager)).thenReturn(LABEL_LOCATION);
when(mPackageManager.getPermissionGroupInfo(eq(PERM_MICROPHONE), anyInt())) when(mPackageManager.getPermissionGroupInfo(eq(PERM_MICROPHONE), anyInt()))
.thenReturn(mGroupMic); .thenReturn(mGroupMic);
when(mGroupMic.loadLabel(mPackageManager)).thenReturn(LABEL_MICROPHONE); when(mGroupMic.loadLabel(mPackageManager)).thenReturn(LABEL_MICROPHONE);
when(mPackageManager.getPermissionGroupInfo(eq(PERM_CAMERA), anyInt())) when(mPackageManager.getPermissionGroupInfo(eq(PERM_CAMERA), anyInt()))
.thenReturn(mGroupCamera); .thenReturn(mGroupCamera);
when(mGroupCamera.loadLabel(mPackageManager)).thenReturn(LABEL_CAMERA); when(mGroupCamera.loadLabel(mPackageManager)).thenReturn(LABEL_CAMERA);
when(mPackageManager.getPermissionGroupInfo(eq(PERM_SMS), anyInt())).thenReturn(mGroupSms); when(mPackageManager.getPermissionGroupInfo(eq(PERM_SMS), anyInt())).thenReturn(mGroupSms);
when(mGroupSms.loadLabel(mPackageManager)).thenReturn(LABEL_SMS); when(mGroupSms.loadLabel(mPackageManager)).thenReturn(LABEL_SMS);
when(mPackageManager.getPermissionGroupInfo(eq(PERM_CONTACTS), anyInt())) when(mPackageManager.getPermissionGroupInfo(eq(PERM_CONTACTS), anyInt()))
.thenReturn(mGroupContacts); .thenReturn(mGroupContacts);
when(mGroupContacts.loadLabel(mPackageManager)).thenReturn(LABEL_CONTACTS); when(mGroupContacts.loadLabel(mPackageManager)).thenReturn(LABEL_CONTACTS);
when(mPackageManager.getPermissionGroupInfo(eq(PERM_PHONE), anyInt())) when(mPackageManager.getPermissionGroupInfo(eq(PERM_PHONE), anyInt()))
.thenReturn(mGroupPhone); .thenReturn(mGroupPhone);
when(mGroupPhone.loadLabel(mPackageManager)).thenReturn(LABEL_PHONE); when(mGroupPhone.loadLabel(mPackageManager)).thenReturn(LABEL_PHONE);
// create permissions // create permissions
@@ -139,7 +141,7 @@ public class AppPermissionsPreferenceControllerTest {
permissions.add(mPermContacts); permissions.add(mPermContacts);
permissions.add(mPermPhone); permissions.add(mPermPhone);
when(mPackageManager.queryPermissionsByGroup(anyString(), anyInt())) when(mPackageManager.queryPermissionsByGroup(anyString(), anyInt()))
.thenReturn(permissions); .thenReturn(permissions);
mController = spy(new AppPermissionsPreferenceController(mContext)); mController = spy(new AppPermissionsPreferenceController(mContext));
} }
@@ -155,7 +157,7 @@ public class AppPermissionsPreferenceControllerTest {
final PackageInfo info = new PackageInfo(); final PackageInfo info = new PackageInfo();
installedPackages.add(info); installedPackages.add(info);
when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)) when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
.thenReturn(installedPackages); .thenReturn(installedPackages);
mController.updateState(mPreference); mController.updateState(mPreference);
@@ -168,7 +170,7 @@ public class AppPermissionsPreferenceControllerTest {
final PackageInfo info = new PackageInfo(); final PackageInfo info = new PackageInfo();
installedPackages.add(info); installedPackages.add(info);
when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)) when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
.thenReturn(installedPackages); .thenReturn(installedPackages);
PermissionInfo[] permissions = new PermissionInfo[4]; PermissionInfo[] permissions = new PermissionInfo[4];
info.permissions = permissions; info.permissions = permissions;
@@ -177,33 +179,38 @@ public class AppPermissionsPreferenceControllerTest {
permissions[2] = mPermCamera; permissions[2] = mPermCamera;
permissions[3] = mPermSms; permissions[3] = mPermSms;
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setSummary("Apps using location, microphone, camera");
verify(mPreference).setSummary("Apps using location, microphone, and camera");
permissions[0] = mPermPhone; permissions[0] = mPermPhone;
permissions[1] = mPermMic; permissions[1] = mPermMic;
permissions[2] = mPermCamera; permissions[2] = mPermCamera;
permissions[3] = mPermSms; permissions[3] = mPermSms;
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setSummary("Apps using microphone, camera, sms");
verify(mPreference).setSummary("Apps using microphone, camera, and sms");
permissions[0] = mPermPhone; permissions[0] = mPermPhone;
permissions[1] = mPermMic; permissions[1] = mPermMic;
permissions[2] = mPermContacts; permissions[2] = mPermContacts;
permissions[3] = mPermSms; permissions[3] = mPermSms;
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setSummary("Apps using microphone, sms, contacts");
verify(mPreference).setSummary("Apps using microphone, sms, and contacts");
permissions = new PermissionInfo[2]; permissions = new PermissionInfo[2];
info.permissions = permissions; info.permissions = permissions;
permissions[0] = mPermLocation; permissions[0] = mPermLocation;
permissions[1] = mPermCamera; permissions[1] = mPermCamera;
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setSummary("Apps using location, camera");
verify(mPreference).setSummary("Apps using location and camera");
permissions = new PermissionInfo[1]; permissions = new PermissionInfo[1];
info.permissions = permissions; info.permissions = permissions;
permissions[0] = mPermCamera; permissions[0] = mPermCamera;
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setSummary("Apps using camera"); verify(mPreference).setSummary("Apps using camera");
} }
} }

View File

@@ -91,44 +91,51 @@ public class DefaultAppSettingsTest {
when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1"); when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1");
when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1"); when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1");
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Browser1, Phone1, Sms1");
verify(summaryLoader).setSummary(summaryProvider, "Browser1, Phone1, and Sms1");
// 2 available // 2 available
when(defaultSms.getDefaultAppLabel()).thenReturn(null); when(defaultSms.getDefaultAppLabel()).thenReturn(null);
when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1"); when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1");
when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1"); when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1");
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Browser1, Phone1");
verify(summaryLoader).setSummary(summaryProvider, "Browser1 and Phone1");
when(defaultSms.getDefaultAppLabel()).thenReturn("Sms1"); when(defaultSms.getDefaultAppLabel()).thenReturn("Sms1");
when(defaultBrowser.getDefaultAppLabel()).thenReturn(null); when(defaultBrowser.getDefaultAppLabel()).thenReturn(null);
when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1"); when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1");
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Phone1, Sms1");
verify(summaryLoader).setSummary(summaryProvider, "Phone1 and Sms1");
when(defaultSms.getDefaultAppLabel()).thenReturn("Sms1"); when(defaultSms.getDefaultAppLabel()).thenReturn("Sms1");
when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1"); when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1");
when(defaultPhone.getDefaultAppLabel()).thenReturn(null); when(defaultPhone.getDefaultAppLabel()).thenReturn(null);
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Phone1, Sms1");
verify(summaryLoader).setSummary(summaryProvider, "Browser1 and Sms1");
// 1 available // 1 available
when(defaultSms.getDefaultAppLabel()).thenReturn(null); when(defaultSms.getDefaultAppLabel()).thenReturn(null);
when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1"); when(defaultBrowser.getDefaultAppLabel()).thenReturn("Browser1");
when(defaultPhone.getDefaultAppLabel()).thenReturn(null); when(defaultPhone.getDefaultAppLabel()).thenReturn(null);
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Browser1"); verify(summaryLoader).setSummary(summaryProvider, "Browser1");
when(defaultSms.getDefaultAppLabel()).thenReturn("Sms1"); when(defaultSms.getDefaultAppLabel()).thenReturn("Sms1");
when(defaultBrowser.getDefaultAppLabel()).thenReturn(null); when(defaultBrowser.getDefaultAppLabel()).thenReturn(null);
when(defaultPhone.getDefaultAppLabel()).thenReturn(null); when(defaultPhone.getDefaultAppLabel()).thenReturn(null);
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Sms1"); verify(summaryLoader).setSummary(summaryProvider, "Sms1");
when(defaultSms.getDefaultAppLabel()).thenReturn(null); when(defaultSms.getDefaultAppLabel()).thenReturn(null);
when(defaultBrowser.getDefaultAppLabel()).thenReturn(null); when(defaultBrowser.getDefaultAppLabel()).thenReturn(null);
when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1"); when(defaultPhone.getDefaultAppLabel()).thenReturn("Phone1");
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader).setSummary(summaryProvider, "Phone1"); verify(summaryLoader).setSummary(summaryProvider, "Phone1");
// None available // None available
@@ -136,6 +143,7 @@ public class DefaultAppSettingsTest {
when(defaultBrowser.getDefaultAppLabel()).thenReturn(null); when(defaultBrowser.getDefaultAppLabel()).thenReturn(null);
when(defaultPhone.getDefaultAppLabel()).thenReturn(null); when(defaultPhone.getDefaultAppLabel()).thenReturn(null);
summaryProvider.setListening(true); summaryProvider.setListening(true);
verify(summaryLoader, never()).setSummary(summaryProvider, eq(anyString())); verify(summaryLoader, never()).setSummary(summaryProvider, eq(anyString()));
} }

View File

@@ -17,8 +17,7 @@
package com.android.settings.inputmethod; package com.android.settings.inputmethod;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -28,11 +27,12 @@ import android.app.admin.DevicePolicyManager;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import androidx.core.text.BidiFormatter;
import androidx.preference.Preference;
import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import androidx.core.text.BidiFormatter;
import androidx.preference.Preference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -125,18 +125,9 @@ public class VirtualKeyboardPreferenceControllerTest {
when(imis.get(0).loadLabel(mPm)).thenReturn(label1); when(imis.get(0).loadLabel(mPm)).thenReturn(label1);
when(imis.get(1).getPackageName()).thenReturn(componentName.getPackageName()); when(imis.get(1).getPackageName()).thenReturn(componentName.getPackageName());
when(imis.get(1).loadLabel(mPm)).thenReturn(label2); when(imis.get(1).loadLabel(mPm)).thenReturn(label2);
when(mContext.getString(eq(R.string.join_many_items_middle), anyString(), anyString()))
.thenAnswer(invocation -> {
final Object[] args = invocation.getArguments();
final String str1 = (String) args[1];
final String str2 = (String) args[2];
return RuntimeEnvironment.application.getString(R.string.join_many_items_middle,
str1, str2);
});
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setSummary( verify(mPreference).setSummary(formatter.unicodeWrap(label1) + " and " + formatter.unicodeWrap(label2));
formatter.unicodeWrap(label1) + ", " + formatter.unicodeWrap(label2));
} }
} }