diff options
Diffstat (limited to 'java/com/android/dialer/contacts/displaypreference')
5 files changed, 380 insertions, 0 deletions
diff --git a/java/com/android/dialer/contacts/displaypreference/AndroidManifest.xml b/java/com/android/dialer/contacts/displaypreference/AndroidManifest.xml new file mode 100644 index 000000000..27514615e --- /dev/null +++ b/java/com/android/dialer/contacts/displaypreference/AndroidManifest.xml @@ -0,0 +1,18 @@ +<!-- + ~ Copyright (C) 2018 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 + --> +<manifest + package="com.android.dialer.contacts.displaypreference"> +</manifest>
\ No newline at end of file diff --git a/java/com/android/dialer/contacts/displaypreference/ContactDisplayPreferences.java b/java/com/android/dialer/contacts/displaypreference/ContactDisplayPreferences.java new file mode 100644 index 000000000..dca466ebf --- /dev/null +++ b/java/com/android/dialer/contacts/displaypreference/ContactDisplayPreferences.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 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.dialer.contacts.displaypreference; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.text.TextUtils; +import java.util.Arrays; + +/** Handles name ordering of a contact (Given name first or family name first.) */ +public interface ContactDisplayPreferences { + + /** + * A enum whose value is a String from a Android string resource which can only be resolved at run + * time. + */ + interface StringResEnum { + + @StringRes + int getStringRes(); + + default String getValue(Context context) { + return context.getString(getStringRes()); + } + + static <T extends Enum<T> & StringResEnum> T fromValue( + Context context, T[] values, String value) { + return Arrays.stream(values) + .filter(enumValue -> TextUtils.equals(enumValue.getValue(context), value)) + // MoreCollectors.onlyElement() is not available to android guava. + .reduce( + (a, b) -> { + throw new AssertionError("multiple result"); + }) + .get(); + } + } + + /** Order when displaying the name; */ + enum DisplayOrder implements StringResEnum { + + /** + * The default display order of a name. For western names it will be "Given Family". For + * unstructured names like east asian this will be the only order. + * + * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY + */ + PRIMARY(R.string.display_options_view_given_name_first_value), + /** + * The alternative display order of a name. For western names it will be "Family, Given". For + * unstructured names like east asian this order will be ignored and treated as primary. + * + * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_ALTERNATIVE + */ + ALTERNATIVE(R.string.display_options_view_family_name_first_value); + + @StringRes private final int value; + + DisplayOrder(@StringRes int value) { + this.value = value; + } + + @Override + @StringRes + public int getStringRes() { + return value; + } + + static DisplayOrder fromValue(Context context, String value) { + return StringResEnum.fromValue(context, DisplayOrder.values(), value); + } + } + + /** + * Order when sorting the name. In some conventions, names are displayed as given name first, but + * sorted by family name. + */ + enum SortOrder implements StringResEnum { + /** + * Sort by the default display order of a name. For western names it will be "Given Family". For + * unstructured names like east asian this will be the only order. + * + * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY + */ + BY_PRIMARY(R.string.display_options_sort_by_given_name_value), + /** + * Sort by the alternative display order of a name. For western names it will be "Family, + * Given". For unstructured names like east asian this order will be ignored and treated as + * primary. + * + * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_ALTERNATIVE + */ + BY_ALTERNATIVE(R.string.display_options_sort_by_family_name_value); + + @StringRes private final int value; + + SortOrder(@StringRes int value) { + this.value = value; + } + + @Override + @StringRes + public int getStringRes() { + return value; + } + + static SortOrder fromValue(Context context, String value) { + return StringResEnum.fromValue(context, SortOrder.values(), value); + } + } + + DisplayOrder getDisplayOrder(); + + void setDisplayOrder(DisplayOrder displayOrder); + + SortOrder getSortOrder(); + + void setSortOrder(SortOrder sortOrder); + + /** Selects display name based on {@link DisplayOrder} */ + default String getDisplayName(@Nullable String primaryName, @Nullable String alternativeName) { + if (TextUtils.isEmpty(alternativeName)) { + return primaryName; + } + switch (getDisplayOrder()) { + case PRIMARY: + return primaryName; + case ALTERNATIVE: + return alternativeName; + } + throw new AssertionError("exhaustive switch"); + } + + /** Selects sort name based on {@link SortOrder} */ + default String getSortName(@Nullable String primaryName, @Nullable String alternativeName) { + if (TextUtils.isEmpty(alternativeName)) { + return primaryName; + } + switch (getSortOrder()) { + case BY_PRIMARY: + return primaryName; + case BY_ALTERNATIVE: + return alternativeName; + } + throw new AssertionError("exhaustive switch"); + } +} diff --git a/java/com/android/dialer/contacts/displaypreference/ContactDisplayPreferencesImpl.java b/java/com/android/dialer/contacts/displaypreference/ContactDisplayPreferencesImpl.java new file mode 100644 index 000000000..6072cc12c --- /dev/null +++ b/java/com/android/dialer/contacts/displaypreference/ContactDisplayPreferencesImpl.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2018 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.dialer.contacts.displaypreference; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.UserManager; +import android.preference.PreferenceManager; +import com.android.dialer.inject.ApplicationContext; +import javax.inject.Inject; + +/** Implementation of {@link ContactDisplayPreferences} backed by a {@link SharedPreferences} */ +public final class ContactDisplayPreferencesImpl implements ContactDisplayPreferences { + + private final Context appContext; + private final SharedPreferences sharedPreferences; + private final String displayOrderKey; + private final String sortOrderKey; + + @Inject + ContactDisplayPreferencesImpl(@ApplicationContext Context appContext) { + this.appContext = appContext; + // @Unencrypted preference would be a better choice, but Android Preference only supports the + // default file. Names cannot be shown on @Unencrypted anyway. + this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext); + displayOrderKey = appContext.getString(R.string.display_options_view_names_as_key); + sortOrderKey = appContext.getString(R.string.display_options_sort_list_by_key); + } + + @Override + public DisplayOrder getDisplayOrder() { + migrate(); + if (!sharedPreferences.contains(displayOrderKey)) { + return DisplayOrder.PRIMARY; + } + return DisplayOrder.fromValue(appContext, sharedPreferences.getString(displayOrderKey, null)); + } + + @Override + public void setDisplayOrder(DisplayOrder displayOrder) { + sharedPreferences.edit().putString(displayOrderKey, displayOrder.getValue(appContext)).apply(); + } + + @Override + public SortOrder getSortOrder() { + migrate(); + if (!sharedPreferences.contains(sortOrderKey)) { + return SortOrder.BY_PRIMARY; + } + return SortOrder.fromValue(appContext, sharedPreferences.getString(sortOrderKey, null)); + } + + @Override + public void setSortOrder(SortOrder sortOrder) { + sharedPreferences.edit().putString(sortOrderKey, sortOrder.getValue(appContext)).apply(); + } + + /** + * Moves the stored values to the standard location. + * + * <p>Usually preferences are stored in {@code package.name_preferences.xml}. However the old + * com.android.contacts.common.preference.ContactsPreferences stored it in {@code + * package.name.xml} which is incompatible with the regular {@link android.preference.Preference} + * widgets. + */ + private void migrate() { + if (!appContext.getSystemService(UserManager.class).isUserUnlocked()) { + return; + } + SharedPreferences oldPreference = + appContext.getSharedPreferences(appContext.getPackageName(), Context.MODE_PRIVATE); + if (oldPreference.contains(displayOrderKey) || oldPreference.contains(sortOrderKey)) { + sharedPreferences + .edit() + .putString( + displayOrderKey, + translateLegacyDisplayOrder(oldPreference.getInt(displayOrderKey, 1))) + .putString(sortOrderKey, translateLegacySortOrder(oldPreference.getInt(sortOrderKey, 1))) + .apply(); + oldPreference.edit().remove(displayOrderKey).remove(sortOrderKey).apply(); + } + } + + private String translateLegacyDisplayOrder(int legacyValue) { + switch (legacyValue) { + case 2: + return DisplayOrder.ALTERNATIVE.getValue(appContext); + default: + return DisplayOrder.PRIMARY.getValue(appContext); + } + } + + private String translateLegacySortOrder(int legacyValue) { + switch (legacyValue) { + case 2: + return SortOrder.BY_ALTERNATIVE.getValue(appContext); + default: + return SortOrder.BY_PRIMARY.getValue(appContext); + } + } +} diff --git a/java/com/android/dialer/contacts/displaypreference/res/values/display_preference.xml b/java/com/android/dialer/contacts/displaypreference/res/values/display_preference.xml new file mode 100644 index 000000000..b74b8b999 --- /dev/null +++ b/java/com/android/dialer/contacts/displaypreference/res/values/display_preference.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 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. + --> +<resources> + <string-array name="contact_display_order_entries"> + <item>@string/display_options_view_given_name_first</item> + <item>@string/display_options_view_family_name_first</item> + </string-array> + + <string-array name="contact_display_order_values"> + <item>@string/display_options_view_given_name_first_value</item> + <item>@string/display_options_view_family_name_first_value</item> + </string-array> + + <string-array name="contact_sort_order_entries"> + <item>@string/display_options_sort_by_given_name</item> + <item>@string/display_options_sort_by_family_name</item> + </string-array> + + <string-array name="contact_sort_order_values"> + <item>@string/display_options_sort_by_given_name_value</item> + <item>@string/display_options_sort_by_family_name_value</item> + </string-array> +</resources>
\ No newline at end of file diff --git a/java/com/android/dialer/contacts/displaypreference/res/values/strings.xml b/java/com/android/dialer/contacts/displaypreference/res/values/strings.xml new file mode 100644 index 000000000..8914ddfa4 --- /dev/null +++ b/java/com/android/dialer/contacts/displaypreference/res/values/strings.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Contact preferences related strings --> + + <!-- Label of the "sort by" display option --> + <string name="display_options_sort_list_by">Sort by</string> + + <string translatable="false" name="display_options_sort_list_by_key">android.contacts.SORT_ORDER</string> + + <!-- An allowable value for the "sort list by" contact display option --> + <string name="display_options_sort_by_given_name">First name</string> + + <string translatable="false" name="display_options_sort_by_given_name_value">sort_by_given_name</string> + + <!-- An allowable value for the "sort list by" contact display option --> + <string name="display_options_sort_by_family_name">Last name</string> + + <string translatable="false" name="display_options_sort_by_family_name_value">sort_by_family_name</string> + + <!-- Label of the "name format" display option [CHAR LIMIT=64]--> + <string name="display_options_view_names_as">Name format</string> + <string translatable="false" name="display_options_view_names_as_key">android.contacts.DISPLAY_ORDER</string> + + <!-- An allowable value for the "view names as" contact display option --> + <string name="display_options_view_given_name_first">First name first</string> + + <string translatable="false" name="display_options_view_given_name_first_value">view_given_name_first</string> + + <!-- An allowable value for the "view names as" contact display option --> + <string name="display_options_view_family_name_first">Last name first</string> + + <string translatable="false" name="display_options_view_family_name_first_value">view_family_name_first</string> +</resources> |