LayoutBase.java revision 139773d0167a2cf09c4b6c2c47aa7d980dc413bd
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 17package com.android.inputmethod.keyboard.layout; 18 19import com.android.inputmethod.keyboard.KeyboardId; 20import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 21import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; 22import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; 23import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; 24import com.android.inputmethod.latin.Constants; 25 26import java.util.Locale; 27 28/** 29 * The base class of keyboard layout. 30 */ 31public abstract class LayoutBase extends AbstractLayoutBase { 32 33 /** 34 * This class is used to customize common keyboard layout to language specific layout. 35 */ 36 public static class LayoutCustomizer { 37 private final Locale mLocale; 38 39 // Empty keys definition to remove keys by adding this. 40 protected static final ExpectedKey[] EMPTY_KEYS = joinKeys(); 41 42 public LayoutCustomizer(final Locale locale) { 43 mLocale = locale; 44 } 45 46 public final Locale getLocale() { 47 return mLocale; 48 } 49 50 /** 51 * Set accented letters to common layout. 52 * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard 53 * layout. 54 * @return the {@link ExpectedKeyboardBuilder} object that contains accented letters as 55 * "more keys". 56 */ 57 public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { 58 return builder; 59 } 60 61 /** 62 * Get the function key to switch to alphabet layout. 63 * @return the {@link ExpectedKey} of the alphabet key. 64 */ 65 public ExpectedKey getAlphabetKey() { return ALPHABET_KEY; } 66 67 /** 68 * Get the function key to switch to symbols layout. 69 * @return the {@link ExpectedKey} of the symbols key. 70 */ 71 public ExpectedKey getSymbolsKey() { return SYMBOLS_KEY; } 72 73 /** 74 * Get the function key to switch to symbols shift layout. 75 * @param isPhone true if requesting phone's key. 76 * @return the {@link ExpectedKey} of the symbols shift key. 77 */ 78 public ExpectedKey getSymbolsShiftKey(boolean isPhone) { 79 return isPhone ? SYMBOLS_SHIFT_KEY : TABLET_SYMBOLS_SHIFT_KEY; 80 } 81 82 /** 83 * Get the function key to switch from symbols shift to symbols layout. 84 * @return the {@link ExpectedKey} of the back to symbols key. 85 */ 86 public ExpectedKey getBackToSymbolsKey() { return BACK_TO_SYMBOLS_KEY; } 87 88 /** 89 * Get the currency key. 90 * @return the {@link ExpectedKey} of the currency key. 91 */ 92 public ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_DOLLAR; } 93 94 /** 95 * Get other currencies keys. 96 * @return the array of {@link ExpectedKey} that represents other currency keys. 97 */ 98 public ExpectedKey[] getOtherCurrencyKeys() { 99 return SymbolsShifted.CURRENCIES_OTHER_THAN_DOLLAR; 100 } 101 102 /** 103 * Get "more keys" of double quotation mark. 104 * @return the array of {@link ExpectedKey} of more double quotation marks in natural order. 105 */ 106 public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_9LR; } 107 108 /** 109 * Get "more keys" of single quotation mark. 110 * @return the array of {@link ExpectedKey} of more single quotation marks in natural order. 111 */ 112 public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_9LR; } 113 114 /** 115 * Get double angle quotation marks in natural order. 116 * @return the array of {@link ExpectedKey} of double angle quotation marks in natural 117 * order. 118 */ 119 public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_LR; } 120 121 /** 122 * Get single angle quotation marks in natural order. 123 * @return the array of {@link ExpectedKey} of single angle quotation marks in natural 124 * order. 125 */ 126 public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_LR; } 127 128 /** 129 * Get the left shift keys. 130 * @param isPhone true if requesting phone's keys. 131 * @return the array of {@link ExpectedKey} that should be placed at left edge of the 132 * keyboard. 133 */ 134 public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { 135 return joinKeys(SHIFT_KEY); 136 } 137 138 /** 139 * Get the right shift keys. 140 * @param isPhone true if requesting phone's keys. 141 * @return the array of {@link ExpectedKey} that should be placed at right edge of the 142 * keyboard. 143 */ 144 public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { 145 return isPhone ? EMPTY_KEYS : joinKeys(EXCLAMATION_AND_QUESTION_MARKS, SHIFT_KEY); 146 } 147 148 /** 149 * Get the space keys. 150 * @param isPhone true if requesting phone's keys. 151 * @return the array of {@link ExpectedKey} that should be placed at the center of the 152 * keyboard. 153 */ 154 public ExpectedKey[] getSpaceKeys(final boolean isPhone) { 155 return joinKeys(LANGUAGE_SWITCH_KEY, SPACE_KEY); 156 } 157 158 /** 159 * Get the keys left to the spacebar. 160 * @param isPhone true if requesting phone's keys. 161 * @return the array of {@link ExpectedKey} that should be placed at left of the spacebar. 162 */ 163 public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) { 164 return isPhone ? joinKeys(key(SHORTCUT_KEY, SETTINGS_KEY)) : joinKeys("/"); 165 } 166 167 /** 168 * Get the keys right to the spacebar. 169 * @param isPhone true if requesting phone's keys. 170 * @return the array of {@link ExpectedKey} that should be placed at right of the spacebar. 171 */ 172 public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { 173 final ExpectedKey periodKey = key(".", getPunctuationMoreKeys(isPhone)); 174 return isPhone ? joinKeys(periodKey) : joinKeys(",", periodKey); 175 } 176 177 /** 178 * Get "more keys" for the punctuation key (usually the period key). 179 * @param isPhone true if requesting phone's keys. 180 * @return the array of {@link ExpectedKey} that are "more keys" of the punctuation key. 181 */ 182 public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { 183 return isPhone ? PHONE_PUNCTUATION_MORE_KEYS : TABLET_PUNCTUATION_MORE_KEYS; 184 } 185 } 186 187 /** 188 * The layout customize class for countries that use Euro. 189 */ 190 public static class EuroCustomizer extends LayoutCustomizer { 191 public EuroCustomizer(final Locale locale) { 192 super(locale); 193 } 194 195 @Override 196 public final ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_EURO; } 197 198 @Override 199 public final ExpectedKey[] getOtherCurrencyKeys() { 200 return SymbolsShifted.CURRENCIES_OTHER_THAN_EURO; 201 } 202 } 203 204 private final LayoutCustomizer mCustomizer; 205 private final Symbols mSymbols; 206 private final SymbolsShifted mSymbolsShifted; 207 208 LayoutBase(final LayoutCustomizer customizer, final Class<? extends Symbols> symbolsClass, 209 final Class<? extends SymbolsShifted> symbolsShiftedClass) { 210 mCustomizer = customizer; 211 try { 212 mSymbols = symbolsClass.getDeclaredConstructor(LayoutCustomizer.class) 213 .newInstance(customizer); 214 mSymbolsShifted = symbolsShiftedClass.getDeclaredConstructor(LayoutCustomizer.class) 215 .newInstance(customizer); 216 } catch (final Exception e) { 217 throw new RuntimeException("Unknown Symbols/SymbolsShifted class", e); 218 } 219 } 220 221 /** 222 * The layout name. 223 * @return the name of this layout. 224 */ 225 public abstract String getName(); 226 227 /** 228 * The locale of this layout. 229 * @return the locale of this layout. 230 */ 231 public final Locale getLocale() { return mCustomizer.getLocale(); } 232 233 /** 234 * The layout customizer for this layout. 235 * @return the layout customizer; 236 */ 237 public final LayoutCustomizer getCustomizer() { return mCustomizer; } 238 239 // Icon id. 240 private static final int ICON_SHIFT = KeyboardIconsSet.getIconId( 241 KeyboardIconsSet.NAME_SHIFT_KEY); 242 private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId( 243 KeyboardIconsSet.NAME_SHIFT_KEY_SHIFTED); 244 private static final int ICON_ZWNJ = KeyboardIconsSet.getIconId( 245 KeyboardIconsSet.NAME_ZWNJ_KEY); 246 private static final int ICON_ZWJ = KeyboardIconsSet.getIconId( 247 KeyboardIconsSet.NAME_ZWJ_KEY); 248 249 // Functional key. 250 static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK); 251 static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT, 252 Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY); 253 static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT, 254 Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY); 255 static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL); 256 static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL); 257 static final ExpectedKey BACK_TO_SYMBOLS_KEY = key("?123", Constants.CODE_SHIFT); 258 static final ExpectedKey SYMBOLS_SHIFT_KEY = key("= \\ <", Constants.CODE_SHIFT); 259 static final ExpectedKey TABLET_SYMBOLS_SHIFT_KEY = key("~ [ <", Constants.CODE_SHIFT); 260 261 // U+00A1: "¡" INVERTED EXCLAMATION MARK 262 // U+00BF: "¿" INVERTED QUESTION MARK 263 static final ExpectedKey[] EXCLAMATION_AND_QUESTION_MARKS = joinKeys( 264 key("!", moreKey("\u00A1")), key("?", moreKey("\u00BF"))); 265 // U+200C: ZERO WIDTH NON-JOINER 266 // U+200D: ZERO WIDTH JOINER 267 static final ExpectedKey ZWNJ_KEY = key(ICON_ZWNJ, "\u200C"); 268 static final ExpectedKey ZWJ_KEY = key(ICON_ZWJ, "\u200D"); 269 270 // Punctuation more keys for phone form factor. 271 public static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys( 272 ",", "?", "!", "#", ")", "(", "/", ";", 273 "'", "@", ":", "-", "\"", "+", "%", "&"); 274 // Punctuation more keys for tablet form factor. 275 public static final ExpectedKey[] TABLET_PUNCTUATION_MORE_KEYS = joinKeys( 276 ",", "'", "#", ")", "(", "/", ";", 277 "@", ":", "-", "\"", "+", "%", "&"); 278 279 /** 280 * Helper method to create alphabet layout adding special function keys. 281 * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard 282 * layout 283 * @param isPhone true if requesting phone's layout. 284 * @return the {@link ExpectedKeyboardBuilder} object that is customized and have special keys. 285 */ 286 ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, 287 final boolean isPhone) { 288 final LayoutCustomizer customizer = getCustomizer(); 289 builder.setKeysOfRow(4, (Object[])customizer.getSpaceKeys(isPhone)); 290 builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); 291 builder.addKeysOnTheRightOfRow(4, (Object[])customizer.getKeysRightToSpacebar(isPhone)); 292 if (isPhone) { 293 builder.addKeysOnTheRightOfRow(3, DELETE_KEY) 294 .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey()) 295 .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY)); 296 } else { 297 builder.addKeysOnTheRightOfRow(1, DELETE_KEY) 298 .addKeysOnTheRightOfRow(2, ENTER_KEY) 299 .addKeysOnTheLeftOfRow(4, 300 customizer.getSymbolsKey(), key(SHORTCUT_KEY, SETTINGS_KEY)) 301 .addKeysOnTheRightOfRow(4, EMOJI_KEY); 302 } 303 builder.addKeysOnTheLeftOfRow(3, (Object[])customizer.getLeftShiftKeys(isPhone)) 304 .addKeysOnTheRightOfRow(3, (Object[])customizer.getRightShiftKeys(isPhone)); 305 return builder; 306 } 307 308 /** 309 * Get common alphabet layout. This layout doesn't contain any special keys. 310 * @param isPhone true if requesting phone's layout. 311 * @return the common alphabet keyboard layout. 312 */ 313 abstract ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone); 314 315 /** 316 * Get common alphabet shifted layout. This layout doesn't contain any special keys. 317 * @param isPhone true if requesting phone's layout. 318 * @param elementId the element id of the requesting shifted mode. 319 * @return the common alphabet shifted keyboard layout. 320 */ 321 ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { 322 final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder( 323 getCommonAlphabetLayout(isPhone)); 324 getCustomizer().setAccentedLetters(builder); 325 builder.toUpperCase(getLocale()); 326 return builder.build(); 327 } 328 329 /** 330 * Get the complete expected keyboard layout. 331 * @param isPhone true if requesting phone's layout. 332 * @param elementId the element id of the requesting keyboard mode. 333 * @return 334 */ 335 public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) { 336 if (elementId == KeyboardId.ELEMENT_SYMBOLS) { 337 return mSymbols.getLayout(isPhone); 338 } 339 if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { 340 return mSymbolsShifted.getLayout(isPhone); 341 } 342 final ExpectedKeyboardBuilder builder; 343 if (elementId == KeyboardId.ELEMENT_ALPHABET) { 344 builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone)); 345 getCustomizer().setAccentedLetters(builder); 346 } else { 347 final ExpectedKey[][] commonLayout = getCommonAlphabetShiftLayout(isPhone, elementId); 348 if (commonLayout == null) { 349 return null; 350 } 351 builder = new ExpectedKeyboardBuilder(commonLayout); 352 } 353 convertCommonLayoutToKeyboard(builder, isPhone); 354 if (elementId != KeyboardId.ELEMENT_ALPHABET) { 355 builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY); 356 } 357 return builder.build(); 358 } 359} 360