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