15ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette/* 25ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Copyright (C) 2011 The Android Open Source Project 35ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 45ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 55ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * you may not use this file except in compliance with the License. 65ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * You may obtain a copy of the License at 75ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 85ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 95ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 105ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Unless required by applicable law or agreed to in writing, software 115ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 125ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * See the License for the specific language governing permissions and 145ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * limitations under the License. 155ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 165ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 175ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverettepackage com.android.inputmethod.accessibility; 185ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 195ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.content.Context; 205ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.content.SharedPreferences; 215ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.text.TextUtils; 225ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 23e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaokaimport com.android.inputmethod.keyboard.Key; 245ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.keyboard.Keyboard; 255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.keyboard.KeyboardId; 265ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.latin.R; 275ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 285ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport java.util.HashMap; 295ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 305ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverettepublic class KeyCodeDescriptionMapper { 3158e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette // The resource ID of the string spoken for obscured keys 3258e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette private static final int OBSCURED_KEY_RES_ID = R.string.spoken_description_dot; 3358e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette 345ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static KeyCodeDescriptionMapper sInstance = new KeyCodeDescriptionMapper(); 355ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 365ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Map of key labels to spoken description resource IDs 375ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private final HashMap<CharSequence, Integer> mKeyLabelMap; 385ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 395ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Map of key codes to spoken description resource IDs 405ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private final HashMap<Integer, Integer> mKeyCodeMap; 415ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 425ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Map of shifted key codes to spoken description resource IDs 435ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private final HashMap<Integer, Integer> mShiftedKeyCodeMap; 445ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 455ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Map of shift-locked key codes to spoken description resource IDs 465ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private final HashMap<Integer, Integer> mShiftLockedKeyCodeMap; 475ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 485ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public static void init(Context context, SharedPreferences prefs) { 495ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette sInstance.initInternal(context, prefs); 505ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 515ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 525ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public static KeyCodeDescriptionMapper getInstance() { 535ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return sInstance; 545ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 555ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private KeyCodeDescriptionMapper() { 575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyLabelMap = new HashMap<CharSequence, Integer>(); 585ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap = new HashMap<Integer, Integer>(); 595ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mShiftedKeyCodeMap = new HashMap<Integer, Integer>(); 605ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mShiftLockedKeyCodeMap = new HashMap<Integer, Integer>(); 615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 625ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 635ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private void initInternal(Context context, SharedPreferences prefs) { 645ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Manual label substitutions for key labels with no string resource 655ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyLabelMap.put(":-)", R.string.spoken_description_smiley); 665ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 675ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Symbols that most TTS engines can't speak 685ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '.', R.string.spoken_description_period); 695ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) ',', R.string.spoken_description_comma); 705ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '(', R.string.spoken_description_left_parenthesis); 715ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) ')', R.string.spoken_description_right_parenthesis); 725ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) ':', R.string.spoken_description_colon); 735ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) ';', R.string.spoken_description_semicolon); 745ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '!', R.string.spoken_description_exclamation_mark); 755ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '?', R.string.spoken_description_question_mark); 765ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\"', R.string.spoken_description_double_quote); 775ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\'', R.string.spoken_description_single_quote); 785ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '*', R.string.spoken_description_star); 795ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '#', R.string.spoken_description_pound); 805ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) ' ', R.string.spoken_description_space); 815ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 825ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Non-ASCII symbols (must use escape codes!) 835ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u2022', R.string.spoken_description_dot); 845ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u221A', R.string.spoken_description_square_root); 855ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u03C0', R.string.spoken_description_pi); 865ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u0394', R.string.spoken_description_delta); 875ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u2122', R.string.spoken_description_trademark); 885ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u2105', R.string.spoken_description_care_of); 895ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u2026', R.string.spoken_description_ellipsis); 905ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put((int) '\u201E', R.string.spoken_description_low_double_quote); 910464850e6c27eaad642b9dacad44e654cab120aeTadashi G. Takaoka mKeyCodeMap.put((int) '\uFF0A', R.string.spoken_description_star); 925ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 935ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Special non-character codes defined in Keyboard 945ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_DELETE, R.string.spoken_description_delete); 955ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_ENTER, R.string.spoken_description_return); 965ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_SETTINGS, R.string.spoken_description_settings); 975ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift); 985ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_SHORTCUT, R.string.spoken_description_mic); 995ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol); 1005ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mKeyCodeMap.put(Keyboard.CODE_TAB, R.string.spoken_description_tab); 1015ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1025ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Shifted versions of non-character codes defined in Keyboard 1035ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mShiftedKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift_shifted); 1045ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1055ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Shift-locked versions of non-character codes defined in Keyboard 1065ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mShiftLockedKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_caps_lock); 1075ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1085ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1095ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 1105ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Returns the localized description of the action performed by a specified 1115ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * key based on the current keyboard state. 1125ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <p> 1135ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * The order of precedence for key descriptions is: 1145ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <ol> 1155ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Manually-defined based on the key label</li> 1165ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Automatic or manually-defined based on the key code</li> 1175ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Automatically based on the key label</li> 1185ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>{code null} for keys with no label or key code defined</li> 1195ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * </p> 1205ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 1215ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param context The package's context. 1225ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param keyboard The keyboard on which the key resides. 1235ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param key The key from which to obtain a description. 12458e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured. 1255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return a character sequence describing the action performed by pressing 1265ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the key 1275ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 12858e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette public CharSequence getDescriptionForKey(Context context, Keyboard keyboard, Key key, 12958e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette boolean shouldObscure) { 1305ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (key.mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { 1315ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final CharSequence description = getDescriptionForSwitchAlphaSymbol(context, keyboard); 1325ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (description != null) 1335ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return description; 1345ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1355ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1365ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (!TextUtils.isEmpty(key.mLabel)) { 1375ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final String label = key.mLabel.toString().trim(); 1385ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1395ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (mKeyLabelMap.containsKey(label)) { 1405ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(mKeyLabelMap.get(label)); 1415ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else if (label.length() == 1 1425ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette || (keyboard.isManualTemporaryUpperCase() && !TextUtils 143520a297ad1d148a57bcf6559a9802d5d49182d70Tadashi G. Takaoka .isEmpty(key.mHintLabel))) { 14458e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); 1455ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else { 1465ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return label; 1475ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1485ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else if (key.mCode != Keyboard.CODE_DUMMY) { 14958e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); 1505ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1515ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1525ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return null; 1535ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1545ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1555ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 1565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Returns a context-specific description for the CODE_SWITCH_ALPHA_SYMBOL 1575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * key or {@code null} if there is not a description provided for the 1585ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * current keyboard context. 1595ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 1605ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param context The package's context. 1615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param keyboard The keyboard on which the key resides. 1625ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return a character sequence describing the action performed by pressing 1635ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the key 1645ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 1655ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private CharSequence getDescriptionForSwitchAlphaSymbol(Context context, Keyboard keyboard) { 1665ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final KeyboardId id = keyboard.mId; 1675ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1685ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (id.isAlphabetKeyboard()) { 1695ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(R.string.spoken_description_to_symbol); 1705ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else if (id.isSymbolsKeyboard()) { 1715ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(R.string.spoken_description_to_alpha); 17260ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka } else if (id.isPhoneShiftKeyboard()) { 1735ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(R.string.spoken_description_to_numeric); 1745ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else if (id.isPhoneKeyboard()) { 1755ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(R.string.spoken_description_to_symbol); 1765ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else { 1775ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return null; 1785ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1795ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1805ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1815ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 1825ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Returns the keycode for the specified key given the current keyboard 1835ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * state. 1845ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 1855ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param keyboard The keyboard on which the key resides. 1865ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param key The key from which to obtain a key code. 1875ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return the key code for the specified key 1885ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 1895ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private int getCorrectKeyCode(Keyboard keyboard, Key key) { 190520a297ad1d148a57bcf6559a9802d5d49182d70Tadashi G. Takaoka if (keyboard.isManualTemporaryUpperCase() && !TextUtils.isEmpty(key.mHintLabel)) { 191520a297ad1d148a57bcf6559a9802d5d49182d70Tadashi G. Takaoka return key.mHintLabel.charAt(0); 1925ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else { 1935ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return key.mCode; 1945ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1955ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1965ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1975ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 1985ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Returns a localized character sequence describing what will happen when 1995ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the specified key is pressed based on its key code. 2005ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <p> 2015ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * The order of precedence for key code descriptions is: 2025ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <ol> 2035ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Manually-defined shift-locked description</li> 2045ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Manually-defined shifted description</li> 2055ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Manually-defined normal description</li> 2065ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Automatic based on the character represented by the key code</li> 2075ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * <li>Fall-back for undefined or control characters</li> 2085ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * </ol> 2095ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * </p> 2105ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 2115ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param context The package's context. 2125ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param keyboard The keyboard on which the key resides. 2135ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param key The key from which to obtain a description. 21458e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured. 2155ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return a character sequence describing the action performed by pressing 2165ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the key 2175ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 21858e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette private CharSequence getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key, 21958e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette boolean shouldObscure) { 2205ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final int code = getCorrectKeyCode(keyboard, key); 2215ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 2225ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) { 2235ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(mShiftLockedKeyCodeMap.get(code)); 2245ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else if (keyboard.isShiftedOrShiftLocked() && mShiftedKeyCodeMap.containsKey(code)) { 2255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(mShiftedKeyCodeMap.get(code)); 22658e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette } 22758e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette 22858e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette // If the key description should be obscured, now is the time to do it. 22958e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette final boolean isDefinedNonCtrl = Character.isDefined(code) && !Character.isISOControl(code); 23058e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette if (shouldObscure && isDefinedNonCtrl) { 23158e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette return context.getString(OBSCURED_KEY_RES_ID); 23258e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette } 23358e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette 23458e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette if (mKeyCodeMap.containsKey(code)) { 2355ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(mKeyCodeMap.get(code)); 23658e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette } else if (isDefinedNonCtrl) { 2375ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return Character.toString((char) code); 2385ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } else { 2395ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return context.getString(R.string.spoken_description_unknown, code); 2405ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 2415ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 2425ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette} 243