1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.dialer.contacts.displaypreference;
18 
19 import android.content.Context;
20 import android.support.annotation.Nullable;
21 import android.support.annotation.StringRes;
22 import android.text.TextUtils;
23 import java.util.Arrays;
24 
25 /** Handles name ordering of a contact (Given name first or family name first.) */
26 public interface ContactDisplayPreferences {
27 
28   /**
29    * A enum whose value is a String from a Android string resource which can only be resolved at run
30    * time.
31    */
32   interface StringResEnum {
33 
34     @StringRes
getStringRes()35     int getStringRes();
36 
getValue(Context context)37     default String getValue(Context context) {
38       return context.getString(getStringRes());
39     }
40 
fromValue( Context context, T[] values, String value)41     static <T extends Enum<T> & StringResEnum> T fromValue(
42         Context context, T[] values, String value) {
43       return Arrays.stream(values)
44           .filter(enumValue -> TextUtils.equals(enumValue.getValue(context), value))
45           // MoreCollectors.onlyElement() is not available to android guava.
46           .reduce(
47               (a, b) -> {
48                 throw new AssertionError("multiple result");
49               })
50           .get();
51     }
52   }
53 
54   /** Order when displaying the name; */
55   enum DisplayOrder implements StringResEnum {
56 
57     /**
58      * The default display order of a name. For western names it will be "Given Family". For
59      * unstructured names like east asian this will be the only order.
60      *
61      * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
62      */
63     PRIMARY(R.string.display_options_view_given_name_first_value),
64     /**
65      * The alternative display order of a name. For western names it will be "Family, Given". For
66      * unstructured names like east asian this order will be ignored and treated as primary.
67      *
68      * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_ALTERNATIVE
69      */
70     ALTERNATIVE(R.string.display_options_view_family_name_first_value);
71 
72     @StringRes private final int value;
73 
DisplayOrder(@tringRes int value)74     DisplayOrder(@StringRes int value) {
75       this.value = value;
76     }
77 
78     @Override
79     @StringRes
getStringRes()80     public int getStringRes() {
81       return value;
82     }
83 
fromValue(Context context, String value)84     static DisplayOrder fromValue(Context context, String value) {
85       return StringResEnum.fromValue(context, DisplayOrder.values(), value);
86     }
87   }
88 
89   /**
90    * Order when sorting the name. In some conventions, names are displayed as given name first, but
91    * sorted by family name.
92    */
93   enum SortOrder implements StringResEnum {
94     /**
95      * Sort by the default display order of a name. For western names it will be "Given Family". For
96      * unstructured names like east asian this will be the only order.
97      *
98      * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
99      */
100     BY_PRIMARY(R.string.display_options_sort_by_given_name_value),
101     /**
102      * Sort by the alternative display order of a name. For western names it will be "Family,
103      * Given". For unstructured names like east asian this order will be ignored and treated as
104      * primary.
105      *
106      * @see android.provider.ContactsContract.Contacts#DISPLAY_NAME_ALTERNATIVE
107      */
108     BY_ALTERNATIVE(R.string.display_options_sort_by_family_name_value);
109 
110     @StringRes private final int value;
111 
SortOrder(@tringRes int value)112     SortOrder(@StringRes int value) {
113       this.value = value;
114     }
115 
116     @Override
117     @StringRes
getStringRes()118     public int getStringRes() {
119       return value;
120     }
121 
fromValue(Context context, String value)122     static SortOrder fromValue(Context context, String value) {
123       return StringResEnum.fromValue(context, SortOrder.values(), value);
124     }
125   }
126 
getDisplayOrder()127   DisplayOrder getDisplayOrder();
128 
setDisplayOrder(DisplayOrder displayOrder)129   void setDisplayOrder(DisplayOrder displayOrder);
130 
getSortOrder()131   SortOrder getSortOrder();
132 
setSortOrder(SortOrder sortOrder)133   void setSortOrder(SortOrder sortOrder);
134 
135   /** Selects display name based on {@link DisplayOrder} */
getDisplayName(@ullable String primaryName, @Nullable String alternativeName)136   default String getDisplayName(@Nullable String primaryName, @Nullable String alternativeName) {
137     if (TextUtils.isEmpty(alternativeName)) {
138       return primaryName;
139     }
140     switch (getDisplayOrder()) {
141       case PRIMARY:
142         return primaryName;
143       case ALTERNATIVE:
144         return alternativeName;
145     }
146     throw new AssertionError("exhaustive switch");
147   }
148 
149   /** Selects sort name based on {@link SortOrder} */
getSortName(@ullable String primaryName, @Nullable String alternativeName)150   default String getSortName(@Nullable String primaryName, @Nullable String alternativeName) {
151     if (TextUtils.isEmpty(alternativeName)) {
152       return primaryName;
153     }
154     switch (getSortOrder()) {
155       case BY_PRIMARY:
156         return primaryName;
157       case BY_ALTERNATIVE:
158         return alternativeName;
159     }
160     throw new AssertionError("exhaustive switch");
161   }
162 }
163