1 /*
2  * Copyright (C) 2017 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.dialpadview;
18 
19 import android.content.Context;
20 import android.support.annotation.NonNull;
21 import android.support.v4.util.SimpleArrayMap;
22 import com.android.dialer.common.Assert;
23 import com.android.dialer.i18n.LocaleUtils;
24 
25 /** A class containing character mappings for the dialpad. */
26 public class DialpadCharMappings {
27 
28   /** The character mapping for the Latin alphabet (the default mapping) */
29   private static class Latin {
30     private static final String[] KEY_TO_CHARS = {
31       "+" /* 0 */,
32       "" /* 1 */,
33       "ABC" /* 2 */,
34       "DEF" /* 3 */,
35       "GHI" /* 4 */,
36       "JKL" /* 5 */,
37       "MNO" /* 6 */,
38       "PQRS" /* 7 */,
39       "TUV" /* 8 */,
40       "WXYZ" /* 9 */,
41       "" /* * */,
42       "" /* # */,
43     };
44 
45     private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
46         getCharToKeyMap(KEY_TO_CHARS);
47   }
48 
49   /** The character mapping for the Bulgarian alphabet */
50   private static class Bul {
51     private static final String[] KEY_TO_CHARS = {
52       "" /* 0 */,
53       "" /* 1 */,
54       "АБВГ" /* 2 */,
55       "ДЕЖЗ" /* 3 */,
56       "ИЙКЛ" /* 4 */,
57       "МНО" /* 5 */,
58       "ПРС" /* 6 */,
59       "ТУФХ" /* 7 */,
60       "ЦЧШЩ" /* 8 */,
61       "ЪЬЮЯ" /* 9 */,
62       "" /* * */,
63       "" /* # */,
64     };
65 
66     private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
67         getCharToKeyMap(KEY_TO_CHARS);
68   }
69 
70   /** The character mapping for the Russian alphabet */
71   private static class Rus {
72     private static final String[] KEY_TO_CHARS = {
73       "" /* 0 */,
74       "" /* 1 */,
75       "АБВГ" /* 2 */,
76       "ДЕЁЖЗ" /* 3 */,
77       "ИЙКЛ" /* 4 */,
78       "МНОП" /* 5 */,
79       "РСТУ" /* 6 */,
80       "ФХЦЧ" /* 7 */,
81       "ШЩЪЫ" /* 8 */,
82       "ЬЭЮЯ" /* 9 */,
83       "" /* * */,
84       "" /* # */,
85     };
86 
87     private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
88         getCharToKeyMap(KEY_TO_CHARS);
89   }
90 
91   /** The character mapping for the Ukrainian alphabet */
92   private static class Ukr {
93     private static final String[] KEY_TO_CHARS = {
94       "" /* 0 */,
95       "" /* 1 */,
96       "АБВГҐ" /* 2 */,
97       "ДЕЄЖЗ" /* 3 */,
98       "ИІЇЙКЛ" /* 4 */,
99       "МНОП" /* 5 */,
100       "РСТУ" /* 6 */,
101       "ФХЦЧ" /* 7 */,
102       "ШЩ" /* 8 */,
103       "ЬЮЯ" /* 9 */,
104       "" /* * */,
105       "" /* # */,
106     };
107 
108     private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
109         getCharToKeyMap(KEY_TO_CHARS);
110   }
111 
112   // A map in which each key is an ISO 639-2 language code and the corresponding value is a
113   // character-key map.
114   private static final SimpleArrayMap<String, SimpleArrayMap<Character, Character>>
115       CHAR_TO_KEY_MAPS = new SimpleArrayMap<>();
116 
117   // A map in which each key is an ISO 639-2 language code and the corresponding value is an array
118   // defining a key-characters map.
119   private static final SimpleArrayMap<String, String[]> KEY_TO_CHAR_MAPS = new SimpleArrayMap<>();
120 
121   static {
122     CHAR_TO_KEY_MAPS.put("bul", Bul.CHAR_TO_KEY);
123     CHAR_TO_KEY_MAPS.put("rus", Rus.CHAR_TO_KEY);
124     CHAR_TO_KEY_MAPS.put("ukr", Ukr.CHAR_TO_KEY);
125 
126     KEY_TO_CHAR_MAPS.put("bul", Bul.KEY_TO_CHARS);
127     KEY_TO_CHAR_MAPS.put("rus", Rus.KEY_TO_CHARS);
128     KEY_TO_CHAR_MAPS.put("ukr", Ukr.KEY_TO_CHARS);
129   }
130 
131   /**
132    * Returns the character-key map of the ISO 639-2 language code of the 1st language preference or
133    * null if no character-key map for the language code is defined.
134    */
getCharToKeyMap(@onNull Context context)135   public static SimpleArrayMap<Character, Character> getCharToKeyMap(@NonNull Context context) {
136     return CHAR_TO_KEY_MAPS.get(LocaleUtils.getLocale(context).getISO3Language());
137   }
138 
139   /**
140    * Returns the character-key map of the provided ISO 639-2 language code.
141    *
142    * <p>Note: this method is for implementations of {@link
143    * com.android.dialer.smartdial.map.SmartDialMap} only. {@link #getCharToKeyMap(Context)} should
144    * be used for all other purposes.
145    *
146    * <p>It is the caller's responsibility to ensure the language code is valid and a character
147    * mapping is defined for that language. Otherwise, an exception will be thrown.
148    */
getCharToKeyMap(String languageCode)149   public static SimpleArrayMap<Character, Character> getCharToKeyMap(String languageCode) {
150     SimpleArrayMap<Character, Character> charToKeyMap = CHAR_TO_KEY_MAPS.get(languageCode);
151 
152     return Assert.isNotNull(
153         charToKeyMap, "No character mappings can be found for language code '%s'", languageCode);
154   }
155 
156   /** Returns the default character-key map (the one that uses the Latin alphabet). */
getDefaultCharToKeyMap()157   public static SimpleArrayMap<Character, Character> getDefaultCharToKeyMap() {
158     return Latin.CHAR_TO_KEY;
159   }
160 
161   /**
162    * Returns the key-characters map of the given ISO 639-2 language code of the 1st language
163    * preference or null if no key-characters map for the language code is defined.
164    */
getKeyToCharsMap(@onNull Context context)165   static String[] getKeyToCharsMap(@NonNull Context context) {
166     return KEY_TO_CHAR_MAPS.get(LocaleUtils.getLocale(context).getISO3Language());
167   }
168 
169   /** Returns the default key-characters map (the one that uses the Latin alphabet). */
getDefaultKeyToCharsMap()170   public static String[] getDefaultKeyToCharsMap() {
171     return Latin.KEY_TO_CHARS;
172   }
173 
174   /**
175    * Given a array representing a key-characters map, return its reverse map.
176    *
177    * <p>It is the caller's responsibility to ensure that
178    *
179    * <ul>
180    *   <li>the array contains only 12 elements,
181    *   <li>the 0th element ~ the 9th element are the mappings for keys "0" ~ "9",
182    *   <li>the 10th element is for key "*", and
183    *   <li>the 11th element is for key "#".
184    * </ul>
185    *
186    * @param keyToChars An array representing a key-characters map. It must satisfy the conditions
187    *     above.
188    * @return A character-key map.
189    */
getCharToKeyMap( @onNull String[] keyToChars)190   private static SimpleArrayMap<Character, Character> getCharToKeyMap(
191       @NonNull String[] keyToChars) {
192     Assert.checkArgument(keyToChars.length == 12);
193 
194     SimpleArrayMap<Character, Character> charToKeyMap = new SimpleArrayMap<>();
195 
196     for (int keyIndex = 0; keyIndex < keyToChars.length; keyIndex++) {
197       String chars = keyToChars[keyIndex];
198 
199       for (int j = 0; j < chars.length(); j++) {
200         char c = chars.charAt(j);
201         if (Character.isAlphabetic(c)) {
202           charToKeyMap.put(Character.toLowerCase(c), getKeyChar(keyIndex));
203         }
204       }
205     }
206 
207     return charToKeyMap;
208   }
209 
210   /** Given a key index of the dialpad, returns the corresponding character. */
getKeyChar(int keyIndex)211   private static char getKeyChar(int keyIndex) {
212     Assert.checkArgument(0 <= keyIndex && keyIndex <= 11);
213 
214     switch (keyIndex) {
215       case 10:
216         return '*';
217       case 11:
218         return '#';
219       default:
220         return (char) ('0' + keyIndex);
221     }
222   }
223 }
224