1 /*
2  * Copyright (C) 2014 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.inputmethod.keyboard.layout;
18 
19 import com.android.inputmethod.keyboard.layout.Symbols.RtlSymbols;
20 import com.android.inputmethod.keyboard.layout.SymbolsShifted.RtlSymbolsShifted;
21 import com.android.inputmethod.keyboard.layout.customizer.LayoutCustomizer;
22 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
23 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
24 import com.android.inputmethod.latin.common.Constants;
25 
26 import java.util.Locale;
27 
28 public final class Arabic extends LayoutBase {
29     private static final String LAYOUT_NAME = "arabic";
30 
Arabic(final Locale locale)31     public Arabic(final Locale locale) {
32         super(new ArabicCustomizer(locale), ArabicSymbols.class, ArabicSymbolsShifted.class);
33     }
34 
35     @Override
getName()36     public String getName() { return LAYOUT_NAME; }
37 
38     private static class ArabicCustomizer extends LayoutCustomizer {
ArabicCustomizer(final Locale locale)39         ArabicCustomizer(final Locale locale) { super(locale); }
40 
41         @Override
getAlphabetKey()42         public ExpectedKey getAlphabetKey() { return ARABIC_ALPHABET_KEY; }
43 
44         @Override
getSymbolsKey()45         public ExpectedKey getSymbolsKey() { return ARABIC_SYMBOLS_KEY; }
46 
47         @Override
getBackToSymbolsKey()48         public ExpectedKey getBackToSymbolsKey() { return ARABIC_BACK_TO_SYMBOLS_KEY; }
49 
50         @Override
getDoubleAngleQuoteKeys()51         public ExpectedKey[] getDoubleAngleQuoteKeys() {
52             return RtlSymbols.DOUBLE_ANGLE_QUOTES_LR_RTL;
53         }
54 
55         @Override
getSingleAngleQuoteKeys()56         public ExpectedKey[] getSingleAngleQuoteKeys() {
57             return RtlSymbols.SINGLE_ANGLE_QUOTES_LR_RTL;
58         }
59 
60         @Override
getLeftShiftKeys(final boolean isPhone)61         public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) {
62             return EMPTY_KEYS;
63         }
64 
65         @Override
getRightShiftKeys(final boolean isPhone)66         public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
67             return EMPTY_KEYS;
68         }
69 
70         @Override
getKeysLeftToSpacebar(final boolean isPhone)71         public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
72             if (isPhone) {
73                 // U+060C: "،" ARABIC COMMA
74                 return joinKeys(key("\u060C", SETTINGS_KEY));
75             }
76             // U+060C: "،" ARABIC COMMA
77             // U+061F: "؟" ARABIC QUESTION MARK
78             // U+061B: "؛" ARABIC SEMICOLON
79             return joinKeys(key("\u060C", joinMoreKeys(
80                     ":", "!", "\u061F", "\u061B", "-", "\"", "'", SETTINGS_KEY)));
81         }
82 
83         @Override
getKeysRightToSpacebar(final boolean isPhone)84         public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
85             if (isPhone) {
86                 return super.getKeysRightToSpacebar(isPhone);
87             }
88             // U+060C: "،" ARABIC COMMA
89             // U+061F: "؟" ARABIC QUESTION MARK
90             // U+061B: "؛" ARABIC SEMICOLON
91             return joinKeys(key(".", getPunctuationMoreKeys(isPhone)));
92         }
93 
94         @Override
getPunctuationMoreKeys(final boolean isPhone)95         public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) {
96             return ARABIC_DIACRITICS;
97         }
98 
99         // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
100         // U+200C: ZERO WIDTH NON-JOINER
101         // U+0628: "ب" ARABIC LETTER BEH
102         // U+062C: "ج" ARABIC LETTER JEEM
103         private static final ExpectedKey ARABIC_ALPHABET_KEY = key(
104                 "\u0623\u200C\u0628\u200C\u062C", Constants.CODE_SWITCH_ALPHA_SYMBOL);
105         // U+0663: "٣" ARABIC-INDIC DIGIT THREE
106         // U+0662: "٢" ARABIC-INDIC DIGIT TWO
107         // U+0661: "١" ARABIC-INDIC DIGIT ONE
108         // U+061F: "؟" ARABIC QUESTION MARK
109         private static final ExpectedKey ARABIC_SYMBOLS_KEY = key(
110                 "\u0663\u0662\u0661\u061F", Constants.CODE_SWITCH_ALPHA_SYMBOL);
111         private static final ExpectedKey ARABIC_BACK_TO_SYMBOLS_KEY = key(
112                 "\u0663\u0662\u0661\u061F", Constants.CODE_SHIFT);
113 
114         private static final ExpectedKey[] ARABIC_DIACRITICS = {
115                 // U+0655: "ٕ" ARABIC HAMZA BELOW
116                 // U+0654: "ٔ" ARABIC HAMZA ABOVE
117                 // U+0652: "ْ" ARABIC SUKUN
118                 // U+064D: "ٍ" ARABIC KASRATAN
119                 // U+064C: "ٌ" ARABIC DAMMATAN
120                 // U+064B: "ً" ARABIC FATHATAN
121                 // U+0651: "ّ" ARABIC SHADDA
122                 // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
123                 // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
124                 // U+0653: "ٓ" ARABIC MADDAH ABOVE
125                 // U+0650: "ِ" ARABIC KASRA
126                 // U+064F: "ُ" ARABIC DAMMA
127                 // U+064E: "َ" ARABIC FATHA
128                 // U+0640: "ـ" ARABIC TATWEEL
129                 moreKey(" \u0655", "\u0655"), moreKey(" \u0654", "\u0654"),
130                 moreKey(" \u0652", "\u0652"), moreKey(" \u064D", "\u064D"),
131                 moreKey(" \u064C", "\u064C"), moreKey(" \u064B", "\u064B"),
132                 moreKey(" \u0651", "\u0651"), moreKey(" \u0656", "\u0656"),
133                 moreKey(" \u0670", "\u0670"), moreKey(" \u0653", "\u0653"),
134                 moreKey(" \u0650", "\u0650"), moreKey(" \u064F", "\u064F"),
135                 moreKey(" \u064E", "\u064E"), moreKey("\u0640\u0640\u0640", "\u0640")
136         };
137     }
138 
139     @Override
getCommonAlphabetLayout(final boolean isPhone)140     ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) {
141         if (isPhone) {
142             return ALPHABET_COMMON;
143         }
144         final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON);
145         // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE
146         builder.insertKeysAtRow(3, 2, "\u0626");
147         return builder.build();
148     }
149 
150     @Override
getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId)151     ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
152         return null;
153     }
154 
155     private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
156             .setKeysOfRow(1,
157                     // U+0636: "ض" ARABIC LETTER DAD
158                     // U+0661: "١" ARABIC-INDIC DIGIT ONE
159                     key("\u0636", joinMoreKeys("1", "\u0661")),
160                     // U+0635: "ص" ARABIC LETTER SAD
161                     // U+0662: "٢" ARABIC-INDIC DIGIT TWO
162                     key("\u0635", joinMoreKeys("2", "\u0662")),
163                     // U+062B: "ث" ARABIC LETTER THEH
164                     // U+0663: "٣" ARABIC-INDIC DIGIT THREE
165                     key("\u062B", joinMoreKeys("3", "\u0663")),
166                     // U+0642: "ق" ARABIC LETTER QAF
167                     // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
168                     // U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE
169                     key("\u0642", joinMoreKeys("4", "\u0664", "\u06A8")),
170                     // U+0641: "ف" ARABIC LETTER FEH
171                     // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
172                     // U+06A4: "ڤ" ARABIC LETTER VEH
173                     // U+06A2: "ڢ" ARABIC LETTER FEH WITH DOT MOVED BELOW
174                     // U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW
175                     key("\u0641", joinMoreKeys("5", "\u0665", "\u06A4", "\u06A2", "\u06A5")),
176                     // U+063A: "غ" ARABIC LETTER GHAIN
177                     // U+0666: "٦" ARABIC-INDIC DIGIT SIX
178                     key("\u063A", joinMoreKeys("6", "\u0666")),
179                     // U+0639: "ع" ARABIC LETTER AIN
180                     // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
181                     key("\u0639", joinMoreKeys("7", "\u0667")),
182                     // U+0647: "ه" ARABIC LETTER HEH
183                     // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
184                     // U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
185                     // U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
186                     key("\u0647", joinMoreKeys("8", "\u0668", moreKey("\uFEEB", "\u0647\u200D"))),
187                     // U+062E: "خ" ARABIC LETTER KHAH
188                     // U+0669: "٩" ARABIC-INDIC DIGIT NINE
189                     key("\u062E", joinMoreKeys("9", "\u0669")),
190                     // U+062D: "ح" ARABIC LETTER HAH
191                     // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
192                     key("\u062D", joinMoreKeys("0", "\u0660")),
193                     // U+062C: "ج" ARABIC LETTER JEEM
194                     // U+0686: "چ" ARABIC LETTER TCHEH
195                     key("\u062C", moreKey("\u0686")))
196             .setKeysOfRow(2,
197                     // U+0634: "ش" ARABIC LETTER SHEEN
198                     // U+069C: "ڜ" ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE
199                     key("\u0634", moreKey("\u069C")),
200                     // U+0633: "س" ARABIC LETTER SEEN
201                     "\u0633",
202                     // U+064A: "ي" ARABIC LETTER YEH
203                     // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE
204                     // U+0649: "ى" ARABIC LETTER ALEF MAKSURA
205                     key("\u064A", joinMoreKeys("\u0626", "\u0649")),
206                     // U+0628: "ب" ARABIC LETTER BEH
207                     // U+067E: "پ" ARABIC LETTER PEH
208                     key("\u0628", moreKey("\u067E")),
209                     // U+0644: "ل" ARABIC LETTER LAM
210                     // U+FEFB: "ﻻ" ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
211                     // U+0627: "ا" ARABIC LETTER ALEF
212                     // U+FEF7: "ﻷ" ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
213                     // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
214                     // U+FEF9: "ﻹ" ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
215                     // U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW
216                     // U+FEF5: "ﻵ" ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
217                     // U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE
218                     key("\u0644",
219                             moreKey("\uFEFB", "\u0644\u0627"), moreKey("\uFEF7", "\u0644\u0623"),
220                             moreKey("\uFEF9", "\u0644\u0625"), moreKey("\uFEF5", "\u0644\u0622")),
221                     // U+0627: "ا" ARABIC LETTER ALEF
222                     // U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE
223                     // U+0621: "ء" ARABIC LETTER HAMZA
224                     // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
225                     // U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW
226                     // U+0671: "ٱ" ARABIC LETTER ALEF WASLA
227                     key("\u0627", joinMoreKeys("\u0622", "\u0621", "\u0623", "\u0625", "\u0671")),
228                     // U+062A: "ت" ARABIC LETTER TEH
229                     // U+0646: "ن" ARABIC LETTER NOON
230                     // U+0645: "م" ARABIC LETTER MEEM
231                     "\u062A", "\u0646", "\u0645",
232                     // U+0643: "ك" ARABIC LETTER KAF
233                     // U+06AF: "گ" ARABIC LETTER GAF
234                     // U+06A9: "ک" ARABIC LETTER KEHEH
235                     key("\u0643", joinMoreKeys("\u06AF", "\u06A9")),
236                     // U+0637: "ط" ARABIC LETTER TAH
237                     "\u0637")
238             .setKeysOfRow(3,
239                     // U+0630: "ذ" ARABIC LETTER THAL
240                     // U+0621: "ء" ARABIC LETTER HAMZA
241                     // U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE
242                     // U+0631: "ر" ARABIC LETTER REH
243                     "\u0630", "\u0621", "\u0624", "\u0631",
244                     // U+0649: "ى" ARABIC LETTER ALEF MAKSURA
245                     // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE
246                     key("\u0649", moreKey("\u0626")),
247                     // U+0629: "ة" ARABIC LETTER TEH MARBUTA
248                     // U+0648: "و" ARABIC LETTER WAW
249                     "\u0629", "\u0648",
250                     // U+0632: "ز" ARABIC LETTER ZAIN
251                     // U+0698: "ژ" ARABIC LETTER JEH
252                     key("\u0632", moreKey("\u0698")),
253                     // U+0638: "ظ" ARABIC LETTER ZAH
254                     // U+062F: "د" ARABIC LETTER DAL
255                     "\u0638", "\u062F")
256             .build();
257 
258     private static class ArabicSymbols extends RtlSymbols {
ArabicSymbols(final LayoutCustomizer customizer)259         public ArabicSymbols(final LayoutCustomizer customizer) {
260             super(customizer);
261         }
262 
263         @Override
getLayout(final boolean isPhone)264         public ExpectedKey[][] getLayout(final boolean isPhone) {
265             return new ExpectedKeyboardBuilder(super.getLayout(isPhone))
266                     // U+0661: "١" ARABIC-INDIC DIGIT ONE
267                     // U+00B9: "¹" SUPERSCRIPT ONE
268                     // U+00BD: "½" VULGAR FRACTION ONE HALF
269                     // U+2153: "⅓" VULGAR FRACTION ONE THIRD
270                     // U+00BC: "¼" VULGAR FRACTION ONE QUARTER
271                     // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
272                     .replaceKeyOfLabel("1", key("\u0661",
273                             joinMoreKeys("1", "\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B")))
274                     // U+0662: "٢" ARABIC-INDIC DIGIT TWO
275                     // U+00B2: "²" SUPERSCRIPT TWO
276                     // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
277                     .replaceKeyOfLabel("2", key("\u0662", joinMoreKeys("2", "\u00B2", "\u2154")))
278                     // U+0663: "٣" ARABIC-INDIC DIGIT THREE
279                     // U+00B3: "³" SUPERSCRIPT THREE
280                     // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
281                     // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
282                     .replaceKeyOfLabel("3", key("\u0663",
283                             joinMoreKeys("3", "\u00B3", "\u00BE", "\u215C")))
284                     // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
285                     // U+2074: "⁴" SUPERSCRIPT FOUR
286                     .replaceKeyOfLabel("4", key("\u0664", joinMoreKeys("4", "\u2074")))
287                     // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
288                     // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
289                     .replaceKeyOfLabel("5", key("\u0665", joinMoreKeys("5", "\u215D")))
290                     // U+0666: "٦" ARABIC-INDIC DIGIT SIX
291                     .replaceKeyOfLabel("6", key("\u0666", moreKey("6")))
292                     // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
293                     // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
294                     .replaceKeyOfLabel("7", key("\u0667", joinMoreKeys("7", "\u215E")))
295                     // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
296                     .replaceKeyOfLabel("8", key("\u0668", moreKey("8")))
297                     // U+0669: "٩" ARABIC-INDIC DIGIT NINE
298                     .replaceKeyOfLabel("9", key("\u0669", moreKey("9")))
299                     // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
300                     // U+066B: "٫" ARABIC DECIMAL SEPARATOR
301                     // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
302                     // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
303                     // U+2205: "∅" EMPTY SET
304                     .replaceKeyOfLabel("0", key("\u0660",
305                             joinMoreKeys("0", "\u066B", "\u066C", "\u207F", "\u2205")))
306                     // U+066A: "٪" ARABIC PERCENT SIGN
307                     // U+2030: "‰" PER MILLE SIGN
308                     .replaceKeyOfLabel("%", key("\u066A", joinMoreKeys("%", "\u2030")))
309                     // U+061B: "؛" ARABIC SEMICOLON
310                     .replaceKeyOfLabel(";", key("\u061B", moreKey(";")))
311                     // U+061F: "؟" ARABIC QUESTION MARK
312                     // U+00BF: "¿" INVERTED QUESTION MARK
313                     .replaceKeyOfLabel("?", key("\u061F", joinMoreKeys("?", "\u00BF")))
314                     // U+060C: "،" ARABIC COMMA
315                     .replaceKeyOfLabel(",", "\u060C")
316                     // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
317                     // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS
318                     .replaceKeyOfLabel("(", key("(", ")",
319                             moreKey("\uFD3E", "\uFD3F"), moreKey("<", ">"), moreKey("{", "}"),
320                             moreKey("[", "]")))
321                     // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS
322                     // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
323                     .replaceKeyOfLabel(")", key(")", "(",
324                             moreKey("\uFD3F", "\uFD3E"), moreKey(">", "<"), moreKey("}", "{"),
325                             moreKey("]", "[")))
326                     // U+2605: "★" BLACK STAR
327                     // U+066D: "٭" ARABIC FIVE POINTED STAR
328                     .setMoreKeysOf("*", "\u2605", "\u066D")
329                     .build();
330         }
331     }
332 
333     private static class ArabicSymbolsShifted extends RtlSymbolsShifted {
ArabicSymbolsShifted(final LayoutCustomizer customizer)334         public ArabicSymbolsShifted(final LayoutCustomizer customizer) {
335             super(customizer);
336         }
337 
338         @Override
getLayout(final boolean isPhone)339         public ExpectedKey[][] getLayout(final boolean isPhone) {
340             return new ExpectedKeyboardBuilder(super.getLayout(isPhone))
341                     // U+2022: "•" BULLET
342                     // U+266A: "♪" EIGHTH NOTE
343                     .setMoreKeysOf("\u2022", "\u266A")
344                     // U+060C: "،" ARABIC COMMA
345                     .replaceKeyOfLabel(",", "\u060C")
346                     .build();
347         }
348     }
349 }
350