/src/com/android/inputmethod/norwegian/NorwegianIME.java

http://scandinavian-keyboard.googlecode.com/ · Java · 1712 lines · 1451 code · 141 blank · 120 comment · 408 complexity · 7552d7c9bed3038f311fb6cbb6b6b6f4 MD5 · raw file

  1. /*
  2. * Copyright (C) 2008-2009 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * 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, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.android.inputmethod.norwegian;
  17. import java.io.FileDescriptor;
  18. import java.io.PrintWriter;
  19. import java.util.ArrayList;
  20. import java.util.Date;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Timer;
  24. import java.util.TimerTask;
  25. import android.app.AlertDialog;
  26. import android.content.BroadcastReceiver;
  27. import android.content.Context;
  28. import android.content.DialogInterface;
  29. import android.content.Intent;
  30. import android.content.IntentFilter;
  31. import android.content.SharedPreferences;
  32. import android.content.pm.PackageManager.NameNotFoundException;
  33. import android.content.res.Configuration;
  34. import android.content.res.Resources;
  35. import android.inputmethodservice.InputMethodService;
  36. import android.inputmethodservice.Keyboard;
  37. import android.inputmethodservice.KeyboardView;
  38. import android.media.AudioManager;
  39. import android.os.Debug;
  40. import android.os.Handler;
  41. import android.os.Message;
  42. import android.os.SystemClock;
  43. import android.os.Vibrator;
  44. import android.preference.PreferenceManager;
  45. import android.text.AutoText;
  46. import android.text.TextUtils;
  47. import android.util.Log;
  48. import android.util.PrintWriterPrinter;
  49. import android.util.Printer;
  50. import android.view.KeyEvent;
  51. import android.view.View;
  52. import android.view.Window;
  53. import android.view.WindowManager;
  54. import android.view.inputmethod.CompletionInfo;
  55. import android.view.inputmethod.EditorInfo;
  56. import android.view.inputmethod.InputConnection;
  57. import android.view.inputmethod.InputMethodManager;
  58. /**
  59. * Input method implementation for Qwerty'ish keyboard.
  60. */
  61. public class NorwegianIME extends InputMethodService
  62. implements KeyboardView.OnKeyboardActionListener {
  63. static final boolean DEBUG = false;
  64. static final boolean TRACE = false;
  65. private static final String PREF_KEYBOARD_TYPE = "keyboard_type";
  66. private static final String PREF_KEYBOARD_LAYOUT = "keyboard_layout";
  67. private static final String PREF_DICTIONARY_MANUALLY = "dictionary_manually";
  68. private static final String PREF_DICTIONARY = "dictionary";
  69. private static final String PREF_VIBRATE_ON = "vibrate_enable";
  70. private static final String PREF_VIBRATE_DURATION = "vibrate_duration";
  71. private static final String PREF_VIBRATE_BUG_FIX = "vibrate_bug_fix";
  72. private static final String PREF_SOUND_ON = "sound_on";
  73. private static final String PREF_AUTO_CAP = "auto_cap";
  74. private static final String PREF_SWIPE_ENABLED = "swipe_enabled";
  75. private static final String PREF_SWIPE_UP = "swipe_up";
  76. private static final String PREF_SWIPE_DOWN = "swipe_down";
  77. private static final String PREF_SWIPE_LEFT = "swipe_left";
  78. private static final String PREF_SWIPE_RIGHT = "swipe_right";
  79. private static final String PREF_SWIPE_KEYBOARD_LAYOUT = "swipe_keyboard_layout";
  80. private static final String PREF_SWIPE_DICTIONARY = "swipe_dictionary";
  81. private static final String PREF_SKIN = "skin";
  82. private static final String PREF_QUICK_FIXES = "quick_fixes";
  83. private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
  84. private static final String PREF_AUTO_COMPLETE = "auto_complete";
  85. private static final String PREF_AUTO_DICTIONARY_ENABLE = "auto_dictionary_enable";
  86. private static final String PREF_AUTO_DICTIONARY_LIMIT = "auto_dictionary_limit";
  87. private static final String PREF_AUTO_DICTIONARY_CASE_SENSITIVE = "auto_dictionary_case_sensitive";
  88. private static final String PREF_SPACE_AFTER_PREDICTION = "space_after_prediction";
  89. private static final String PREF_SWAP_COLON = "swap_colon";
  90. private static final String PREF_AT_IS_WORD_SEPARATOR = "at_is_word_separator";
  91. private static final int MSG_UPDATE_SUGGESTIONS = 0;
  92. private static final int MSG_START_TUTORIAL = 1;
  93. private static final int MSG_UPDATE_SHIFT_STATE = 2;
  94. // How many continuous deletes at which to start deleting at a higher speed.
  95. private static final int DELETE_ACCELERATE_AT = 20;
  96. // Key events coming any faster than this are long-presses.
  97. private static final int QUICK_PRESS = 200;
  98. // Weight added to a user picking a new word from the suggestion strip
  99. static final int FREQUENCY_FOR_PICKED = 3;
  100. // Weight added to a user typing a new word that doesn't get corrected (or is reverted)
  101. static final int FREQUENCY_FOR_TYPED = 3; //1;
  102. // A word that is frequently typed and get's promoted to the user dictionary, uses this
  103. // frequency.
  104. static final int FREQUENCY_FOR_AUTO_ADD = 250;
  105. static final int KEYCODE_ENTER = '\n';
  106. static final int KEYCODE_SPACE = ' ';
  107. // Contextual menu positions
  108. private static final int POS_SETTINGS = 0;
  109. private static final int POS_METHOD = 1;
  110. private static final int POS_USER_DICTIONARY = 2;
  111. private static final int POS_LAYOUT = 3;
  112. private static final int POS_DICTIONARY = 4;
  113. private NorwegianKeyboardView mInputView;
  114. private CandidateViewContainer mCandidateViewContainer;
  115. private CandidateView mCandidateView;
  116. private Suggest mSuggest;
  117. private CompletionInfo[] mCompletions;
  118. private AlertDialog mOptionsDialog;
  119. KeyboardSwitcher mKeyboardSwitcher;
  120. private UserDictionary mUserDictionary;
  121. private AutoDictionary mAutoDictionary;
  122. private String mLocale;
  123. private StringBuilder mComposing = new StringBuilder();
  124. private WordComposer mWord = new WordComposer();
  125. private int mCommittedLength;
  126. private boolean mPredicting;
  127. private CharSequence mBestWord;
  128. private boolean mPredictionOn;
  129. private boolean mCompletionOn;
  130. private boolean mAutoSpace;
  131. private boolean mAutoCorrectOn;
  132. private boolean mCapsLock;
  133. private int mKeyboardType;
  134. private int mKeyboardLayout;
  135. private boolean mDictionaryManually;
  136. private String mDictionary;
  137. private CharSequence[] mAvailableDictionaries;
  138. private CharSequence[] mAvailableDictionaryValues;
  139. private boolean mVibrateOn;
  140. private boolean mSoundOn;
  141. private boolean mAutoCap;
  142. private boolean mSwipeEnabled;
  143. private int mSwipeUp;
  144. private int mSwipeDown;
  145. private int mSwipeLeft;
  146. private int mSwipeRight;
  147. private String mSwipeKeyboardLayout;
  148. private String mSwipeDictionary;
  149. private String mSkin;
  150. private String mLastSkin;
  151. private boolean mQuickFixes;
  152. private boolean mShowSuggestions;
  153. private boolean mAutoDictionaryEnabled;
  154. private int mAutoDictionaryLimit;
  155. private boolean mAutoDictionaryCaseSensitive;
  156. private boolean mSpaceAfterPrediction;
  157. private boolean mSwapColon;
  158. private int mCorrectionMode;
  159. private int mOrientation;
  160. // Indicates whether the suggestion strip is to be on in landscape
  161. private boolean mJustAccepted;
  162. private CharSequence mJustRevertedSeparator;
  163. private int mDeleteCount;
  164. private long mLastKeyTime;
  165. private int mLastOnKeyCode;
  166. private int mKeyPressesCount;
  167. private Tutorial mTutorial;
  168. private Vibrator mVibrator;
  169. private long mVibrateDuration = 0;
  170. private long mVibrateStart;
  171. private Timer mVibrateTimer;
  172. private boolean mVibrateBugFix;
  173. private AudioManager mAudioManager;
  174. // Align sound effect volume on music volume
  175. private final float FX_VOLUME = -1.0f;
  176. private boolean mSilentMode;
  177. private String mWordSeparators;
  178. private String mSentenceSeparators;
  179. private String pkgNameLast;
  180. private int resIdLast;
  181. private int lastKeyPressed;
  182. private ArrayList<Integer> validKeyCodes;
  183. private HashMap<Integer, Integer> letterSymbolArray;
  184. Handler mHandler = new Handler() {
  185. @Override
  186. public void handleMessage(Message msg) {
  187. switch (msg.what) {
  188. case MSG_UPDATE_SUGGESTIONS:
  189. updateSuggestions();
  190. break;
  191. case MSG_START_TUTORIAL:
  192. if (mTutorial == null) {
  193. if (mInputView.isShown()) {
  194. mTutorial = new Tutorial(NorwegianIME.this, mInputView);
  195. mTutorial.start();
  196. } else {
  197. // Try again soon if the view is not yet showing
  198. sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
  199. }
  200. }
  201. break;
  202. case MSG_UPDATE_SHIFT_STATE:
  203. updateShiftKeyState(getCurrentInputEditorInfo());
  204. break;
  205. }
  206. }
  207. };
  208. @Override public void onCreate() {
  209. super.onCreate();
  210. //setStatusIcon(R.drawable.ime_qwerty);
  211. mKeyboardSwitcher = new KeyboardSwitcher(this);
  212. final Configuration conf = getResources().getConfiguration();
  213. initSuggest(conf.locale.toString(), true);
  214. mOrientation = conf.orientation;
  215. mVibrateDuration = getResources().getInteger(R.integer.vibrate_duration_ms);
  216. // register to receive ringer mode changes for silent mode
  217. IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
  218. registerReceiver(mReceiver, filter);
  219. }
  220. private void initSuggest(String locale, boolean doAll) {
  221. String pkgName;
  222. FindDictionary dictionaries = new FindDictionary(this);
  223. mAvailableDictionaries = dictionaries.getAppNames();
  224. mAvailableDictionaryValues = dictionaries.getPackageNames();
  225. if(mDictionaryManually)
  226. pkgName = mDictionary;
  227. else {
  228. int index = 0;
  229. CharSequence[] keyboardLayouts = getResources().getStringArray(R.array.keyboard_layouts_values);
  230. for (int i = 0; i < keyboardLayouts.length; i++)
  231. if(mKeyboardLayout == Integer.parseInt(keyboardLayouts[i].toString()))
  232. index = i;
  233. pkgName = dictionaries.findPackageName(getResources().getStringArray(R.array.keyboard_layouts)[index]);
  234. }
  235. int resId = dictionaries.getResId(pkgName);
  236. if(doAll || pkgName != pkgNameLast) {
  237. Resources res;
  238. try {
  239. res = getPackageManager().getResourcesForApplication(pkgName);
  240. } catch(NameNotFoundException notFound) {
  241. res = getResources();
  242. resId = 0;
  243. }
  244. if(doAll || resId != resIdLast || (pkgName != pkgNameLast && resId != 0)) {
  245. mLocale = locale;
  246. mSuggest = new Suggest(this, res, resId); //(this, R.raw.main);
  247. mSuggest.setCorrectionMode(mCorrectionMode, mQuickFixes);
  248. mUserDictionary = new UserDictionary(this);
  249. mAutoDictionary = new AutoDictionary(this);
  250. mSuggest.setUserDictionary(mUserDictionary);
  251. mSuggest.setAutoDictionary(mAutoDictionary);
  252. mWordSeparators = getResources().getString(R.string.word_separators);
  253. mSentenceSeparators = getResources().getString(R.string.sentence_separators);
  254. }
  255. if(resId != 0) pkgNameLast = pkgName;
  256. else pkgNameLast = "";
  257. resIdLast = resId;
  258. }
  259. }
  260. @Override public void onDestroy() {
  261. mUserDictionary.close();
  262. unregisterReceiver(mReceiver);
  263. super.onDestroy();
  264. }
  265. @Override
  266. public void onConfigurationChanged(Configuration conf) {
  267. if (!TextUtils.equals(conf.locale.toString(), mLocale)) {
  268. initSuggest(conf.locale.toString(), true);
  269. }
  270. // If orientation changed while predicting, commit the change
  271. if (conf.orientation != mOrientation) {
  272. commitTyped(getCurrentInputConnection());
  273. mOrientation = conf.orientation;
  274. }
  275. if (mKeyboardSwitcher == null) {
  276. mKeyboardSwitcher = new KeyboardSwitcher(this);
  277. }
  278. mKeyboardSwitcher.makeKeyboards(true);
  279. super.onConfigurationChanged(conf);
  280. }
  281. @Override
  282. public View onCreateInputView() {
  283. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
  284. mSkin = sp.getString(PREF_SKIN, "input_standard");
  285. int layout_input;
  286. boolean changeIcons = true;
  287. if("input_htc".equals(mSkin)) layout_input = R.layout.input_htc;
  288. else if("input_iphone".equals(mSkin)) layout_input = R.layout.input_iphone;
  289. else if("input_light".equals(mSkin)) layout_input = R.layout.input_light;
  290. else {
  291. layout_input = R.layout.input_standard;
  292. changeIcons = false;
  293. }
  294. mLastSkin = mSkin;
  295. mInputView = (NorwegianKeyboardView) getLayoutInflater().inflate(
  296. layout_input, null);
  297. mKeyboardSwitcher.setInputView(mInputView);
  298. mKeyboardSwitcher.makeKeyboards(true);
  299. mInputView.setOnKeyboardActionListener(this);
  300. mKeyboardSwitcher.setKeyboardType(mKeyboardType);
  301. mKeyboardSwitcher.setKeyboardLayout(mKeyboardLayout);
  302. mKeyboardSwitcher.setKeyboardModeChangeIcons(KeyboardSwitcher.MODE_TEXT, 0, changeIcons);
  303. return mInputView;
  304. }
  305. @Override
  306. public View onCreateCandidatesView() {
  307. mKeyboardSwitcher.makeKeyboards(true);
  308. mCandidateViewContainer = (CandidateViewContainer) getLayoutInflater().inflate(
  309. R.layout.candidates, null);
  310. mCandidateViewContainer.initViews();
  311. mCandidateView = (CandidateView) mCandidateViewContainer.findViewById(R.id.candidates);
  312. mCandidateView.setService(this);
  313. setCandidatesViewShown(true);
  314. return mCandidateViewContainer;
  315. }
  316. @Override
  317. public void onStartInputView(EditorInfo attribute, boolean restarting) {
  318. // In landscape mode, this method gets called without the input view being created.
  319. if (mInputView == null) {
  320. return;
  321. }
  322. loadSettings();
  323. if(mSkin != null && !mSkin.equals(mLastSkin))
  324. setInputView(onCreateInputView());
  325. initSuggest(getResources().getConfiguration().locale.toString(), false);
  326. mKeyboardSwitcher.setKeyboardType(mKeyboardType);
  327. mKeyboardSwitcher.setKeyboardLayout(mKeyboardLayout);
  328. mKeyboardSwitcher.makeKeyboards(false);
  329. TextEntryState.newSession(this);
  330. boolean disableAutoCorrect = false;
  331. mPredictionOn = false;
  332. mCompletionOn = false;
  333. mCompletions = null;
  334. mCapsLock = false;
  335. switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) {
  336. case EditorInfo.TYPE_CLASS_NUMBER:
  337. case EditorInfo.TYPE_CLASS_DATETIME:
  338. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_SYMBOLS,
  339. attribute.imeOptions);
  340. break;
  341. case EditorInfo.TYPE_CLASS_PHONE:
  342. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_PHONE,
  343. attribute.imeOptions);
  344. break;
  345. case EditorInfo.TYPE_CLASS_TEXT:
  346. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
  347. attribute.imeOptions);
  348. //startPrediction();
  349. mPredictionOn = true;
  350. // Make sure that passwords are not displayed in candidate view
  351. int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
  352. if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
  353. variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) {
  354. mPredictionOn = false;
  355. }
  356. if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
  357. || variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) {
  358. mAutoSpace = false;
  359. } else {
  360. mAutoSpace = true;
  361. }
  362. if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
  363. mPredictionOn = false;
  364. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_EMAIL,
  365. attribute.imeOptions);
  366. } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
  367. mPredictionOn = false;
  368. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_URL,
  369. attribute.imeOptions);
  370. } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
  371. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_IM,
  372. attribute.imeOptions);
  373. } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
  374. mPredictionOn = false;
  375. } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
  376. // If it's a browser edit field and auto correct is not ON explicitly, then
  377. // disable auto correction, but keep suggestions on.
  378. if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
  379. disableAutoCorrect = true;
  380. }
  381. }
  382. // If NO_SUGGESTIONS is set, don't do prediction.
  383. /*if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
  384. mPredictionOn = false;
  385. disableAutoCorrect = true;
  386. }*/
  387. // If it's not multiline and the autoCorrect flag is not set, then don't correct
  388. if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
  389. (attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
  390. disableAutoCorrect = true;
  391. }
  392. if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
  393. mPredictionOn = false;
  394. mCompletionOn = true && isFullscreenMode();
  395. }
  396. updateShiftKeyState(attribute);
  397. break;
  398. default:
  399. mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
  400. attribute.imeOptions);
  401. updateShiftKeyState(attribute);
  402. }
  403. mInputView.closing();
  404. mComposing.setLength(0);
  405. mPredicting = false;
  406. mDeleteCount = 0;
  407. setCandidatesViewShown(false);
  408. if (mCandidateView != null) mCandidateView.setSuggestions(null, false, false, false);
  409. //loadSettings();
  410. // Override auto correct
  411. if (disableAutoCorrect) {
  412. mAutoCorrectOn = false;
  413. if (mCorrectionMode == Suggest.CORRECTION_FULL) {
  414. mCorrectionMode = Suggest.CORRECTION_BASIC;
  415. }
  416. }
  417. mInputView.setProximityCorrectionEnabled(true);
  418. if (mSuggest != null) {
  419. mSuggest.setCorrectionMode(mCorrectionMode, mQuickFixes);
  420. }
  421. mPredictionOn = mPredictionOn && mCorrectionMode > 0;
  422. checkTutorial(attribute.privateImeOptions);
  423. if (TRACE) Debug.startMethodTracing("/data/trace/norwegianime");
  424. }
  425. @Override
  426. public void onFinishInput() {
  427. super.onFinishInput();
  428. if (mInputView != null) {
  429. mInputView.closing();
  430. }
  431. }
  432. @Override
  433. public void onUpdateSelection(int oldSelStart, int oldSelEnd,
  434. int newSelStart, int newSelEnd,
  435. int candidatesStart, int candidatesEnd) {
  436. super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
  437. candidatesStart, candidatesEnd);
  438. // If the current selection in the text view changes, we should
  439. // clear whatever candidate text we have.
  440. if (mComposing.length() > 0 && mPredicting && (newSelStart != candidatesEnd
  441. || newSelEnd != candidatesEnd)) {
  442. mComposing.setLength(0);
  443. mPredicting = false;
  444. updateSuggestions();
  445. TextEntryState.reset();
  446. InputConnection ic = getCurrentInputConnection();
  447. if (ic != null) {
  448. ic.finishComposingText();
  449. }
  450. } else if (!mPredicting && !mJustAccepted
  451. && TextEntryState.getState() == TextEntryState.STATE_ACCEPTED_DEFAULT) {
  452. TextEntryState.reset();
  453. }
  454. mJustAccepted = false;
  455. postUpdateShiftKeyState();
  456. }
  457. @Override
  458. public void hideWindow() {
  459. if (TRACE) Debug.stopMethodTracing();
  460. if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
  461. mOptionsDialog.dismiss();
  462. mOptionsDialog = null;
  463. }
  464. if (mTutorial != null) {
  465. mTutorial.close();
  466. mTutorial = null;
  467. }
  468. super.hideWindow();
  469. TextEntryState.endSession();
  470. }
  471. @Override
  472. public void onDisplayCompletions(CompletionInfo[] completions) {
  473. if (false) {
  474. Log.i("foo", "Received completions:");
  475. for (int i=0; i<(completions != null ? completions.length : 0); i++) {
  476. Log.i("foo", " #" + i + ": " + completions[i]);
  477. }
  478. }
  479. if (mCompletionOn) {
  480. mCompletions = completions;
  481. if (completions == null) {
  482. mCandidateView.setSuggestions(null, false, false, false);
  483. return;
  484. }
  485. List<CharSequence> stringList = new ArrayList<CharSequence>();
  486. for (int i=0; i<(completions != null ? completions.length : 0); i++) {
  487. CompletionInfo ci = completions[i];
  488. if (ci != null) stringList.add(ci.getText());
  489. }
  490. //CharSequence typedWord = mWord.getTypedWord();
  491. mCandidateView.setSuggestions(stringList, true, true, true);
  492. mBestWord = null;
  493. setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
  494. }
  495. }
  496. @Override
  497. public void setCandidatesViewShown(boolean shown) {
  498. // TODO: Remove this if we support candidates with hard keyboard
  499. if (onEvaluateInputViewShown()) {
  500. super.setCandidatesViewShown(shown);
  501. }
  502. }
  503. @Override
  504. public void onComputeInsets(InputMethodService.Insets outInsets) {
  505. super.onComputeInsets(outInsets);
  506. if (!isFullscreenMode()) {
  507. outInsets.contentTopInsets = outInsets.visibleTopInsets;
  508. }
  509. }
  510. @Override
  511. public boolean onKeyDown(int keyCode, KeyEvent event) {
  512. switch (keyCode) {
  513. case KeyEvent.KEYCODE_BACK:
  514. if (event.getRepeatCount() == 0 && mInputView != null) {
  515. if (mInputView.handleBack()) {
  516. return true;
  517. } else if (mTutorial != null) {
  518. mTutorial.close();
  519. mTutorial = null;
  520. }
  521. }
  522. break;
  523. case KeyEvent.KEYCODE_DPAD_DOWN:
  524. case KeyEvent.KEYCODE_DPAD_UP:
  525. case KeyEvent.KEYCODE_DPAD_LEFT:
  526. case KeyEvent.KEYCODE_DPAD_RIGHT:
  527. // If tutorial is visible, don't allow dpad to work
  528. if (mTutorial != null) {
  529. return true;
  530. }
  531. break;
  532. }
  533. return super.onKeyDown(keyCode, event);
  534. }
  535. @Override
  536. public boolean onKeyUp(int keyCode, KeyEvent event) {
  537. switch (keyCode) {
  538. case KeyEvent.KEYCODE_DPAD_DOWN:
  539. case KeyEvent.KEYCODE_DPAD_UP:
  540. case KeyEvent.KEYCODE_DPAD_LEFT:
  541. case KeyEvent.KEYCODE_DPAD_RIGHT:
  542. // If tutorial is visible, don't allow dpad to work
  543. if (mTutorial != null) {
  544. return true;
  545. }
  546. // Enable shift key and DPAD to do selections
  547. if (mInputView != null && mInputView.isShown() && mInputView.isShifted()) {
  548. event = new KeyEvent(event.getDownTime(), event.getEventTime(),
  549. event.getAction(), event.getKeyCode(), event.getRepeatCount(),
  550. event.getDeviceId(), event.getScanCode(),
  551. KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
  552. InputConnection ic = getCurrentInputConnection();
  553. if (ic != null) ic.sendKeyEvent(event);
  554. return true;
  555. }
  556. break;
  557. }
  558. return super.onKeyUp(keyCode, event);
  559. }
  560. private void commitTyped(InputConnection inputConnection) {
  561. if (mPredicting) {
  562. mPredicting = false;
  563. if (mComposing.length() > 0) {
  564. if (inputConnection != null) {
  565. inputConnection.commitText(mComposing, 1);
  566. }
  567. mCommittedLength = mComposing.length();
  568. TextEntryState.acceptedTyped(mComposing);
  569. if(mAutoDictionaryEnabled)
  570. mAutoDictionary.addWord(mComposing.toString(), FREQUENCY_FOR_TYPED);
  571. }
  572. updateSuggestions();
  573. }
  574. }
  575. private void postUpdateShiftKeyState() {
  576. mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
  577. mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SHIFT_STATE), 300);
  578. }
  579. public void updateShiftKeyState(EditorInfo attr) {
  580. InputConnection ic = getCurrentInputConnection();
  581. if (attr != null && mInputView != null && mKeyboardSwitcher.isAlphabetMode()
  582. && ic != null) {
  583. int caps = 0;
  584. EditorInfo ei = getCurrentInputEditorInfo();
  585. if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
  586. caps = ic.getCursorCapsMode(attr.inputType);
  587. }
  588. mInputView.setShifted(mCapsLock || caps != 0);
  589. }
  590. }
  591. private void swapPunctuationAndSpace() {
  592. final InputConnection ic = getCurrentInputConnection();
  593. if (ic == null) return;
  594. CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
  595. if (lastTwo != null && lastTwo.length() == 2
  596. && lastTwo.charAt(0) == KEYCODE_SPACE && isSentenceSeparator(lastTwo.charAt(1))) {
  597. ic.beginBatchEdit();
  598. ic.deleteSurroundingText(2, 0);
  599. ic.commitText(lastTwo.charAt(1) + " ", 1);
  600. ic.endBatchEdit();
  601. updateShiftKeyState(getCurrentInputEditorInfo());
  602. }
  603. }
  604. private void doubleSpace() {
  605. //if (!mAutoPunctuate) return;
  606. if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
  607. final InputConnection ic = getCurrentInputConnection();
  608. if (ic == null) return;
  609. CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
  610. if (lastThree != null && lastThree.length() == 3
  611. && Character.isLetterOrDigit(lastThree.charAt(0))
  612. && lastThree.charAt(1) == KEYCODE_SPACE && lastThree.charAt(2) == KEYCODE_SPACE) {
  613. ic.beginBatchEdit();
  614. ic.deleteSurroundingText(2, 0);
  615. ic.commitText(". ", 1);
  616. ic.endBatchEdit();
  617. updateShiftKeyState(getCurrentInputEditorInfo());
  618. }
  619. }
  620. public boolean addWordToDictionary(String word) {
  621. mUserDictionary.addWord(word, 128);
  622. return true;
  623. }
  624. private boolean isAlphabet(int code) {
  625. if (Character.isLetter(code)) {
  626. return true;
  627. } else {
  628. return false;
  629. }
  630. }
  631. // Implementation of KeyboardViewListener
  632. public void onKey(int primaryCode, int[] keyCodes) {
  633. long when = SystemClock.uptimeMillis();
  634. if (primaryCode != Keyboard.KEYCODE_DELETE ||
  635. when > mLastKeyTime + QUICK_PRESS) {
  636. mDeleteCount = 0;
  637. }
  638. switch (primaryCode) {
  639. case Keyboard.KEYCODE_DELETE:
  640. handleBackspace();
  641. mDeleteCount++;
  642. break;
  643. case Keyboard.KEYCODE_SHIFT:
  644. handleShift();
  645. break;
  646. case Keyboard.KEYCODE_CANCEL:
  647. if (mOptionsDialog == null || !mOptionsDialog.isShowing()) {
  648. handleClose();
  649. }
  650. break;
  651. case NorwegianKeyboardView.KEYCODE_OPTIONS:
  652. showOptionsMenu();
  653. break;
  654. case NorwegianKeyboardView.KEYCODE_SHIFT_LONGPRESS:
  655. if (mCapsLock) {
  656. handleShift();
  657. } else {
  658. toggleCapsLock();
  659. }
  660. break;
  661. case Keyboard.KEYCODE_MODE_CHANGE:
  662. changeKeyboardMode();
  663. break;
  664. default:
  665. if (isWordSeparator(primaryCode)) {
  666. handleSeparator(primaryCode);
  667. } else {
  668. handleCharacter(primaryCode, keyCodes);
  669. // Postponed until next version. Testing of phone layout
  670. // if(mKeyboardType == 2) {
  671. // mKeyPressesCount++;
  672. // if(primaryCode != mLastOnKeyCode || when > mLastKeyTime + 1000)
  673. // mKeyPressesCount = 0;
  674. // switch(mKeyPressesCount) {
  675. // case 0:
  676. // handleCharacter(primaryCode, keyCodes);
  677. // break;
  678. // case 1:
  679. // replaceLastCharacter(primaryCode + 1, keyCodes);
  680. // break;
  681. // case 2:
  682. // replaceLastCharacter(primaryCode + 2, keyCodes);
  683. // break;
  684. // }
  685. // } else {
  686. // String k = primaryCode + " ";
  687. // for (int i : keyCodes)
  688. // k += i + " ";
  689. // Log.d("SK", k);
  690. // handleCharacter(primaryCode, keyCodes);
  691. // }
  692. }
  693. // Cancel the just reverted state
  694. mJustRevertedSeparator = null;
  695. }
  696. mLastKeyTime = when;
  697. mLastOnKeyCode = primaryCode;
  698. if (mKeyboardSwitcher.onKey(primaryCode)) {
  699. //changeKeyboardMode();
  700. }
  701. }
  702. public void onText(CharSequence text) {
  703. InputConnection ic = getCurrentInputConnection();
  704. if (ic == null) return;
  705. ic.beginBatchEdit();
  706. if (mPredicting) {
  707. commitTyped(ic);
  708. }
  709. ic.commitText(text, 1);
  710. ic.endBatchEdit();
  711. updateShiftKeyState(getCurrentInputEditorInfo());
  712. mJustRevertedSeparator = null;
  713. }
  714. private void handleBackspace() {
  715. boolean deleteChar = false;
  716. InputConnection ic = getCurrentInputConnection();
  717. if (ic == null) return;
  718. if (mPredicting) {
  719. final int length = mComposing.length();
  720. if (length > 0) {
  721. mComposing.delete(length - 1, length);
  722. mWord.deleteLast();
  723. ic.setComposingText(mComposing, 1);
  724. if (mComposing.length() == 0) {
  725. mPredicting = false;
  726. }
  727. postUpdateSuggestions();
  728. } else {
  729. ic.deleteSurroundingText(1, 0);
  730. }
  731. } else {
  732. deleteChar = true;
  733. }
  734. postUpdateShiftKeyState();
  735. TextEntryState.backspace();
  736. if (TextEntryState.getState() == TextEntryState.STATE_UNDO_COMMIT) {
  737. revertLastWord(deleteChar);
  738. return;
  739. } else if (deleteChar) {
  740. sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
  741. if (mDeleteCount > DELETE_ACCELERATE_AT) {
  742. sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
  743. }
  744. }
  745. mJustRevertedSeparator = null;
  746. }
  747. private void handleShift() {
  748. Keyboard currentKeyboard = mInputView.getKeyboard();
  749. if (mKeyboardSwitcher.isAlphabetMode()) {
  750. // Alphabet keyboard
  751. checkToggleCapsLock();
  752. mInputView.setShifted(mCapsLock || !mInputView.isShifted());
  753. } else {
  754. mKeyboardSwitcher.toggleShift();
  755. }
  756. }
  757. private void handleCharacter(int primaryCode, int[] keyCodes) {
  758. if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) {
  759. if (!mPredicting) {
  760. mPredicting = true;
  761. mComposing.setLength(0);
  762. mWord.reset();
  763. }
  764. }
  765. if (mInputView.isShifted()) {
  766. // TODO: This doesn't work with ß, need to fix it in the next release.
  767. if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
  768. || keyCodes[0] > Character.MAX_CODE_POINT) {
  769. return;
  770. }
  771. primaryCode = new String(keyCodes, 0, 1).toUpperCase().charAt(0);
  772. }
  773. if (mPredicting) {
  774. if (mInputView.isShifted() && mComposing.length() == 0) {
  775. mWord.setCapitalized(true);
  776. }
  777. mComposing.append((char) primaryCode);
  778. mWord.add(primaryCode, keyCodes);
  779. InputConnection ic = getCurrentInputConnection();
  780. if (ic != null) {
  781. ic.setComposingText(mComposing, 1);
  782. }
  783. postUpdateSuggestions();
  784. } else {
  785. sendKeyChar((char)primaryCode);
  786. }
  787. updateShiftKeyState(getCurrentInputEditorInfo());
  788. measureCps();
  789. TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode));
  790. }
  791. private void handleSeparator(int primaryCode) {
  792. boolean pickedDefault = false;
  793. // Handle separator
  794. InputConnection ic = getCurrentInputConnection();
  795. if (ic != null) {
  796. ic.beginBatchEdit();
  797. }
  798. if (mPredicting) {
  799. // In certain languages where single quote is a separator, it's better
  800. // not to auto correct, but accept the typed word. For instance,
  801. // in Italian dov' should not be expanded to dove' because the elision
  802. // requires the last vowel to be removed.
  803. if (mAutoCorrectOn && primaryCode != '\'' &&
  804. (mJustRevertedSeparator == null
  805. || mJustRevertedSeparator.length() == 0
  806. || mJustRevertedSeparator.charAt(0) != primaryCode)) {
  807. pickDefaultSuggestion();
  808. pickedDefault = true;
  809. } else {
  810. commitTyped(ic);
  811. }
  812. }
  813. sendKeyChar((char)primaryCode);
  814. TextEntryState.typedCharacter((char) primaryCode, true);
  815. if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED
  816. && primaryCode != KEYCODE_ENTER) {
  817. if(mSwapColon || !":".equals(String.valueOf((char)primaryCode)) && !";".equals(String.valueOf((char)primaryCode)))
  818. swapPunctuationAndSpace();
  819. } else if (isPredictionOn() && primaryCode == ' ') {
  820. //else if (TextEntryState.STATE_SPACE_AFTER_ACCEPTED) {
  821. doubleSpace();
  822. }
  823. if (pickedDefault && mBestWord != null) {
  824. TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
  825. }
  826. updateShiftKeyState(getCurrentInputEditorInfo());
  827. if (ic != null) {
  828. ic.endBatchEdit();
  829. }
  830. }
  831. private void replaceLastCharacter(int primaryCode, int[] keyCodes) {
  832. InputConnection ic = getCurrentInputConnection();
  833. if (ic == null) return;
  834. if (mInputView.isShifted()) {
  835. // TODO: This doesn't work with ß, need to fix it in the next release.
  836. if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
  837. || keyCodes[0] > Character.MAX_CODE_POINT) {
  838. return;
  839. }
  840. primaryCode = new String(keyCodes, 0, 1).toUpperCase().charAt(0);
  841. }
  842. if (mPredicting) {
  843. final int length = mComposing.length();
  844. if (length > 0) {
  845. mComposing.delete(length - 1, length);
  846. mWord.deleteLast();
  847. } else {
  848. ic.deleteSurroundingText(1, 0);
  849. }
  850. if (mInputView.isShifted() && mComposing.length() == 0) {
  851. mWord.setCapitalized(true);
  852. }
  853. mComposing.append((char) primaryCode);
  854. mWord.add(primaryCode, keyCodes);
  855. ic.setComposingText(mComposing, 1);
  856. postUpdateSuggestions();
  857. } else {
  858. sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
  859. sendKeyChar((char)primaryCode);
  860. }
  861. updateShiftKeyState(getCurrentInputEditorInfo());
  862. measureCps();
  863. TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode));
  864. }
  865. private void handleClose() {
  866. commitTyped(getCurrentInputConnection());
  867. requestHideSelf(0);
  868. mInputView.closing();
  869. TextEntryState.endSession();
  870. }
  871. private void checkToggleCapsLock() {
  872. if (mInputView.getKeyboard().isShifted()) {
  873. toggleCapsLock();
  874. }
  875. }
  876. private void toggleCapsLock() {
  877. mCapsLock = !mCapsLock;
  878. if (mKeyboardSwitcher.isAlphabetMode()) {
  879. mInputView.setShifted(mCapsLock); //Needed for 1.5, since keys don't get updated at longpress.
  880. ((NorwegianKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock);
  881. }
  882. }
  883. private void postUpdateSuggestions() {
  884. mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
  885. mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100);
  886. }
  887. private boolean isPredictionOn() {
  888. boolean predictionOn = mPredictionOn;
  889. //if (isFullscreenMode()) predictionOn &= mPredictionLandscape;
  890. return predictionOn;
  891. }
  892. private boolean isCandidateStripVisible() {
  893. return isPredictionOn() && mShowSuggestions;
  894. }
  895. private void updateSuggestions() {
  896. // Check if we have a suggestion engine attached.
  897. if (mSuggest == null || !isPredictionOn()) {
  898. return;
  899. }
  900. if (!mPredicting) {
  901. mCandidateView.setSuggestions(null, false, false, false);
  902. return;
  903. }
  904. List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, mWord, false);
  905. boolean correctionAvailable = mSuggest.hasMinimalCorrection();
  906. //|| mCorrectionMode == mSuggest.CORRECTION_FULL;
  907. CharSequence typedWord = mWord.getTypedWord();
  908. // If we're in basic correct
  909. boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
  910. (preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
  911. if (mCorrectionMode == Suggest.CORRECTION_FULL) {
  912. correctionAvailable |= typedWordValid;
  913. }
  914. // Don't auto-correct words with multiple capital letter
  915. correctionAvailable &= !mWord.isMostlyCaps();
  916. mCandidateView.setSuggestions(stringList, false, typedWordValid, correctionAvailable);
  917. if (stringList.size() > 0) {
  918. if (correctionAvailable && !typedWordValid && stringList.size() > 1) {
  919. mBestWord = stringList.get(1);
  920. } else {
  921. mBestWord = typedWord;
  922. }
  923. } else {
  924. mBestWord = null;
  925. }
  926. setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
  927. }
  928. private void pickDefaultSuggestion() {
  929. // Complete any pending candidate query first
  930. if (mHandler.hasMessages(MSG_UPDATE_SUGGESTIONS)) {
  931. mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
  932. updateSuggestions();
  933. }
  934. if (mBestWord != null) {
  935. TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
  936. mJustAccepted = true;
  937. pickSuggestion(mBestWord);
  938. }
  939. }
  940. public void pickSuggestionManually(int index, CharSequence suggestion) {
  941. if (mCompletionOn && mCompletions != null && index >= 0
  942. && index < mCompletions.length) {
  943. CompletionInfo ci = mCompletions[index];
  944. InputConnection ic = getCurrentInputConnection();
  945. if (ic != null) {
  946. ic.commitCompletion(ci);
  947. }
  948. mCommittedLength = suggestion.length();
  949. if (mCandidateView != null) {
  950. mCandidateView.clear();
  951. }
  952. updateShiftKeyState(getCurrentInputEditorInfo());
  953. return;
  954. }
  955. pickSuggestion(suggestion);
  956. TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
  957. // Follow it with a space
  958. if (mAutoSpace && mSpaceAfterPrediction) {
  959. sendSpace();
  960. }
  961. // Fool the state watcher so that a subsequent backspace will not do a revert
  962. TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
  963. }
  964. private void pickSuggestion(CharSequence suggestion) {
  965. if (mCapsLock) {
  966. suggestion = suggestion.toString().toUpperCase();
  967. } else if (preferCapitalization()
  968. || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted())) {
  969. suggestion = suggestion.toString().toUpperCase().charAt(0)
  970. + suggestion.subSequence(1, suggestion.length()).toString();
  971. }
  972. InputConnection ic = getCurrentInputConnection();
  973. if (ic != null) {
  974. ic.commitText(suggestion, 1);
  975. }
  976. // Add the word to the auto dictionary if it's not a known word
  977. if (mAutoDictionaryEnabled && (mAutoDictionary.isValidWord(suggestion) || !mSuggest.isValidWord(suggestion))) {
  978. mAutoDictionary.addWord(suggestion.toString(), FREQUENCY_FOR_PICKED);
  979. }
  980. mPredicting = false;
  981. mCommittedLength = suggestion.length();
  982. if (mCandidateView != null) {
  983. mCandidateView.setSuggestions(null, false, false, false);
  984. }
  985. updateShiftKeyState(getCurrentInputEditorInfo());
  986. }
  987. private boolean isCursorTouchingWord() {
  988. InputConnection ic = getCurrentInputConnection();
  989. if (ic == null) return false;
  990. CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
  991. CharSequence toRight = ic.getTextAfterCursor(1, 0);
  992. if (!TextUtils.isEmpty(toLeft)
  993. && !isWordSeparator(toLeft.charAt(0))) {
  994. return true;
  995. }
  996. if (!TextUtils.isEmpty(toRight)
  997. && !isWordSeparator(toRight.charAt(0))) {
  998. return true;
  999. }
  1000. return false;
  1001. }
  1002. public void revertLastWord(boolean deleteChar) {
  1003. final int length = mComposing.length();
  1004. if (!mPredicting && length > 0) {
  1005. final InputConnection ic = getCurrentInputConnection();
  1006. mPredicting = true;
  1007. ic.beginBatchEdit();
  1008. mJustRevertedSeparator = ic.getTextBeforeCursor(1, 0);
  1009. if (deleteChar) ic.deleteSurroundingText(1, 0);
  1010. int toDelete = mCommittedLength;
  1011. CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
  1012. if (toTheLeft != null && toTheLeft.length() > 0
  1013. && isWordSeparator(toTheLeft.charAt(0))) {
  1014. toDelete--;
  1015. }
  1016. ic.deleteSurroundingText(toDelete, 0);
  1017. ic.setComposingText(mComposing, 1);
  1018. TextEntryState.backspace();
  1019. ic.endBatchEdit();
  1020. postUpdateSuggestions();
  1021. } else {
  1022. sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
  1023. mJustRevertedSeparator = null;
  1024. }
  1025. }
  1026. protected String getWordSeparators() {
  1027. return mWordSeparators;
  1028. }
  1029. public boolean isWordSeparator(int code) {
  1030. String separators = getWordSeparators();
  1031. return separators.contains(String.valueOf((char)code));
  1032. }
  1033. public boolean isSentenceSeparator(int code) {
  1034. return mSentenceSeparators.contains(String.valueOf((char)code));
  1035. }
  1036. private void sendSpace() {
  1037. sendKeyChar((char)KEYCODE_SPACE);
  1038. updateShiftKeyState(getCurrentInputEditorInfo());
  1039. //onKey(KEY_SPACE[0], KEY_SPACE);
  1040. }
  1041. public boolean preferCapitalization() {
  1042. return mWord.isCapitalized();
  1043. }
  1044. public void swipeRight() {
  1045. // if (NorwegianKeyboardView.DEBUG_AUTO_PLAY) {
  1046. // ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE));
  1047. // CharSequence text = cm.getText();
  1048. // if (!TextUtils.isEmpty(text)) {
  1049. // mInputView.startPlaying(text.toString());
  1050. // }
  1051. // }
  1052. swipe(mSwipeRight);
  1053. }
  1054. public void swipeLeft() {
  1055. swipe(mSwipeLeft);
  1056. }
  1057. public void swipeDown() {
  1058. //handleClose();
  1059. swipe(mSwipeDown);
  1060. }
  1061. public void swipeUp() {
  1062. //launchSettings();
  1063. swipe(mSwipeUp);
  1064. }
  1065. public void swipe(int type) {
  1066. if(mSwipeEnabled) {
  1067. switch(type) {
  1068. case 1:
  1069. if(lastKeyPressed > 0) {
  1070. mInputView.setShifted(!mInputView.isShifted());
  1071. onKey(lastKeyPressed, new int[] { lastKeyPressed });
  1072. }
  1073. return;
  1074. case 2:
  1075. if(96 < lastKeyPressed && lastKeyPressed < 123 || validKeyCodes.contains(lastKeyPressed))
  1076. onKey(letterSymbolArray.get(lastKeyPressed), new int[] { letterSymbolArray.get(lastKeyPressed) });
  1077. return;
  1078. case 3:
  1079. handleBackspace();
  1080. return;
  1081. case 4:
  1082. onKey(KEYCODE_SPACE, new int[] { KEYCODE_SPACE } );
  1083. return;
  1084. case 6:
  1085. handleClose();
  1086. return;
  1087. case 7:
  1088. case 8:
  1089. int newKeyboardLayoutIndex = 0;
  1090. CharSequence[] keyboardLayouts = ListPreferenceMultiSelect.parseStoredValue(mSwipeKeyboardLayout);
  1091. for (int i = 0; i < keyboardLayouts.length; i++)
  1092. if(mKeyboardLayout == Integer.parseInt(keyboardLayouts[i].toString()))
  1093. newKeyboardLayoutIndex = i;
  1094. newKeyboardLayoutIndex = newKeyboardLayoutIndex + (type == 7 ? -1 : 1);
  1095. if(newKeyboardLayoutIndex >= keyboardLayouts.length)
  1096. newKeyboardLayoutIndex = 0;
  1097. else if(newKeyboardLayoutIndex < 0)
  1098. newKeyboardLayoutIndex = keyboardLayouts.length - 1;
  1099. changePreference(PREF_KEYBOARD_LAYOUT, keyboardLayouts[newKeyboardLayoutIndex].toString());
  1100. return;
  1101. case 9:
  1102. case 10:
  1103. int newDictionaryIndex = 0;
  1104. CharSequence[] selectedDictionaries = ListPreferenceMultiSelect.parseStoredValue(mSwipeDictionary);
  1105. for (int i = 0; i < selectedDictionaries.length; i++)
  1106. if(mDictionary.equals(selectedDictionaries[i]))
  1107. newDictionaryIndex = i;
  1108. newDictionaryIndex = newDictionaryIndex + (type == 9 ? -1 : 1);
  1109. if(newDictionaryIndex >= selectedDictionaries.length)
  1110. newDictionaryIndex = 0;
  1111. else if(newDictionaryIndex < 0)
  1112. newDictionaryIndex = selectedDictionaries.length - 1;
  1113. if(!mDictionaryManually) {
  1114. mDictionaryManually = true;
  1115. changePreference(PREF_DICTIONARY_MANUALLY, true);
  1116. }
  1117. changePreference(PREF_DICTIONARY, selectedDictionaries[newDictionaryIndex].toString());
  1118. return;
  1119. case 11:
  1120. getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
  1121. return;
  1122. case 12:
  1123. getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
  1124. return;
  1125. case 13:
  1126. getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
  1127. return;
  1128. case 14:
  1129. getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
  1130. return;
  1131. }
  1132. }
  1133. }
  1134. public void onPress(int primaryCode) {
  1135. vibrate();
  1136. playKeyClick(primaryCode);
  1137. lastKeyPressed = primaryCode;
  1138. }
  1139. public void onRelease(int primaryCode) {
  1140. //vibrate();
  1141. }
  1142. // receive ringer mode changes to detect silent mode
  1143. private BroadcastReceiver mReceiver = new BroadcastReceiver() {
  1144. @Override
  1145. public void onReceive(Context context, Intent intent) {
  1146. updateRingerMode();
  1147. }
  1148. };
  1149. // update flags for silent mode
  1150. private void updateRingerMode() {
  1151. if (mAudioManager == null) {
  1152. mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  1153. }
  1154. if (mAudioManager != null) {
  1155. mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
  1156. }
  1157. }
  1158. private void playKeyClick(int primaryCode) {
  1159. // if mAudioManager is null, we don't have the ringer state yet
  1160. // mAudioManager will be set by updateRingerMode
  1161. if (mAudioManager == null) {
  1162. if (mInputView != null) {
  1163. updateRingerMode();
  1164. }
  1165. }
  1166. if (mSoundOn && !mSilentMode) {
  1167. // FIXME: Volume and enable should come from UI settings
  1168. // FIXME: These should be triggered after auto-repeat logic
  1169. int sound = AudioManager.FX_KEYPRESS_STANDARD;
  1170. switch (primaryCode) {
  1171. case Keyboard.KEYCODE_DELETE:
  1172. sound = AudioManager.FX_KEYPRESS_DELETE;
  1173. break;
  1174. case KEYCODE_ENTER:
  1175. sound = AudioManager.FX_KEYPRESS_RETURN;
  1176. break;
  1177. case KEYCODE_SPACE:
  1178. sound = AudioManager.FX_KEYPRESS_SPACEBAR;
  1179. break;
  1180. }
  1181. mAudioManager.playSoundEffect(sound, FX_VOLUME);
  1182. }
  1183. }
  1184. private void vibrate() {
  1185. if (!mVibrateOn || mVibrateDuration > 100)
  1186. return;
  1187. if (mVibrator == null)
  1188. mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
  1189. mVibrator.vibrate(mVibrateDuration);
  1190. if(mVibrateBugFix) {
  1191. if (mVibrateTimer == null)
  1192. mVibrateTimer = new Timer();
  1193. mVibrateStart = (new Date()).getTime();
  1194. mVibrateTimer.schedule(new TimerTask() {
  1195. @Override
  1196. public void run() {
  1197. if(mVibrateStart == 0) {
  1198. this.cancel();
  1199. mVibrateTimer.purge();
  1200. } else if((new Date()).getTime() > (mVibrateStart + mVibrateDuration)) {
  1201. mVibrateStart = 0;
  1202. mVibrator.cancel();
  1203. this.cancel();
  1204. mVibrateTimer.purge();
  1205. }
  1206. }
  1207. }, mVibrateDuration, 1);
  1208. }
  1209. }
  1210. private void checkTutorial(String privateImeOptions) {
  1211. if (privateImeOptions == null) return;
  1212. if (privateImeOptions.equals("com.android.setupwizard:ShowTutorial")) {
  1213. if (mTutorial == null) startTutorial();
  1214. } else if (privateImeOptions.equals("com.android.setupwizard:HideTutorial")) {
  1215. if (mTutorial != null) {
  1216. if (mTutorial.close()) {
  1217. mTutorial = null;
  1218. }
  1219. }
  1220. }
  1221. }
  1222. private void startTutorial() {
  1223. mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500);
  1224. }
  1225. void tutorialDone() {
  1226. mTutorial = null;
  1227. }
  1228. void promoteToUserDictionary(String word, int frequency) {
  1229. if (mUserDictionary.isValidWord(word)) return;
  1230. mUserDictionary.addWord(word, frequency);
  1231. }
  1232. private void launchSettings() {
  1233. handleClose();
  1234. Intent intent = new Intent();
  1235. intent.setClass(NorwegianIME.this, NorwegianIMESettings.class);
  1236. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1237. startActivity(intent);
  1238. }
  1239. private void loadSettings() {
  1240. // Get the settings preferences
  1241. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
  1242. mKeyboardType = Integer.parseInt(sp.getString(PREF_KEYBOARD_TYPE, getResources().getString(R.string.keyboard_type_list_default_value)));
  1243. mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, true);
  1244. mVibrateDuration = sp.getInt(PREF_VIBRATE_DURATION, getResources().getInteger(R.integer.vibrate_duration_ms));
  1245. mVibrateBugFix = sp.getBoolean(PREF_VIBRATE_BUG_FIX, false);
  1246. mSoundOn = sp.getBoolean(PREF_SOUND_ON, false);
  1247. mAutoCap = sp.getBoolean(PREF_AUTO_CAP, true);
  1248. mSwipeEnabled = sp.getBoolean(PREF_SWIPE_ENABLED, true);
  1249. mSwipeUp = Integer.parseInt(sp.getString(PREF_SWIPE_UP, getResources().getString(R.string.swipe_up_default)));
  1250. mSwipeDown = Integer.parseInt(sp.getString(PREF_SWIPE_DOWN, getResources().getString(R.string.swipe_down_default)));
  1251. mSwipeLeft = Integer.parseInt(sp.getString(PREF_SWIPE_LEFT, getResources().getString(R.string.swipe_left_default)));
  1252. mSwipeRight = Integer.parseInt(sp.getString(PREF_SWIPE_RIGHT, getResources().getString(R.string.swipe_right_default)));
  1253. mSwipeKeyboardLayout = sp.getString(PREF_SWIPE_KEYBOARD_LAYOUT, getResources().getString(R.string.swipe_keyboard_layout));
  1254. mSwipeDictionary = sp.getString(PREF_SWIPE_DICTIONARY, getResources().getString(R.string.swipe_dictionary));
  1255. mSkin = sp.getString(PREF_SKIN, getResources().getString(R.string.skin_default_value));
  1256. mKeyboardLayout = Integer.parseInt(sp.getString(PREF_KEYBOARD_LAYOUT, getResources().getString(R.string.keyboard_layout_list_default_value)));
  1257. mDictionaryManually = sp.getBoolean(PREF_DICTIONARY_MANUALLY, false);
  1258. mDictionary = sp.getString(PREF_DICTIONARY, getResources().getString(R.string.dictionary_list_default_value));
  1259. createLetterSymbolArray();
  1260. mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, false);
  1261. // If there is no auto text data, then quickfix is forced to "on", so that the other options
  1262. // will continue to work
  1263. if (AutoText.getSize(mInputView) < 1) mQuickFixes = true;
  1264. if(mKeyboardLayout != 2 && !mDictionaryManually || mDictionaryManually &&
  1265. !(mDictionary.contains(getResources().getString(R.string.dictionary_builtin_name)) || mDictionary.equals(getResources().getString(R.string.dictionary_builtin_pkg))))
  1266. mQuickFixes = false;
  1267. mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true);// & mQuickFixes;
  1268. boolean autoComplete = sp.getBoolean(PREF_AUTO_COMPLETE,
  1269. getResources().getBoolean(R.bool.enable_autocorrect));// & mShowSuggestions;
  1270. mAutoCorrectOn = mSuggest != null && (autoComplete || mQuickFixes);
  1271. mCorrectionMode = autoComplete
  1272. ? Suggest.CORRECTION_FULL
  1273. : ((mQuickFixes || mShowSuggestions) ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
  1274. mAutoDictionaryEnabled = sp.getBoolean(PREF_AUTO_DICTIONARY_ENABLE, true);
  1275. mAutoDictionaryLimit = Integer.parseInt(sp.getString(PREF_AUTO_DICTIONARY_LIMIT, getResources().getString(R.string.auto_dictionary_limit_default)));
  1276. mAutoDictionaryCaseSensitive = sp.getBoolean(PREF_AUTO_DICTIONARY_CASE_SENSITIVE, false);
  1277. mAutoDictionary.loadSettings();
  1278. mSpaceAfterPrediction = sp.getBoolean(PREF_SPACE_AFTER_PREDICTION, true);;
  1279. mSwapColon = sp.getBoolean(PREF_SWAP_COLON, true);
  1280. boolean atIsWordSeparator = sp.getBoolean(PREF_AT_IS_WORD_SEPARATOR, true);
  1281. if(!atIsWordSeparator)
  1282. mWordSeparators = mWordSeparators.replace("@", "");
  1283. else if(!mWordSeparators.contains("@"))
  1284. mWordSeparators += "@";
  1285. }
  1286. private void showOptionsMenu() {
  1287. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  1288. builder.setCancelable(true);
  1289. builder.setIcon(R.drawable.ic_dialog_keyboard);
  1290. builder.setNegativeButton(android.R.string.cancel, null);
  1291. CharSequence itemSettings = getString(R.string.english_ime_settings);
  1292. CharSequence itemInputMethod = getString(R.string.input_method);
  1293. CharSequence itemKeyboardLayout = getString(R.string.keyboard_layout);
  1294. CharSequence itemDictionaryLanguage = getString(R.string.dictionary);
  1295. CharSequence itemUserDictionary = getString(R.string.user_dict_settings_title);
  1296. CharSequence[] items;
  1297. if(mDictionaryManually)
  1298. items = new CharSequence[] {itemSettings, itemInputMethod, itemUserDictionary, itemKeyboardLayout, itemDictionaryLanguage};
  1299. else
  1300. items = new CharSequence[] {itemSettings, itemInputMethod, itemUserDictionary, itemKeyboardLayout};
  1301. builder.setItems(items,
  1302. new DialogInterface.OnClickListener() {
  1303. public void onClick(DialogInterface di, int position) {
  1304. di.dismiss();
  1305. switch (position) {
  1306. case POS_SETTINGS:
  1307. launchSettings();
  1308. break;
  1309. case POS_METHOD:
  1310. ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
  1311. .showInputMethodPicker();
  1312. break;
  1313. case POS_USER_DICTIONARY:
  1314. launchUserDictionary();
  1315. break;
  1316. case POS_LAYOUT:
  1317. launchChooseLayout();
  1318. break;
  1319. case POS_DICTIONARY:
  1320. launchChooseDictionary();
  1321. break;
  1322. }
  1323. }
  1324. });
  1325. builder.setTitle(getResources().getString(R.string.english_ime_name));
  1326. mOptionsDialog = builder.create();
  1327. Window window = mOptionsDialog.getWindow();
  1328. WindowManager.LayoutParams lp = window.getAttributes();
  1329. lp.token = mInputView.getWindowToken();
  1330. lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
  1331. window.setAttributes(lp);
  1332. window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
  1333. mOptionsDialog.show();
  1334. }
  1335. private void launchUserDictionary() {
  1336. handleClose();
  1337. Intent intent = new Intent(Intent.ACTION_MAIN);
  1338. intent.setClass(NorwegianIME.this, UserDictionarySettings.class);
  1339. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1340. startActivity(intent);
  1341. }
  1342. private void launchChooseLayout() {
  1343. CharSequence[] keyboardLayoutValues = getResources().getTextArray(R.array.keyboard_layouts_values);
  1344. int selectedLayoutIndex = -1;
  1345. for(int i = 0; i < keyboardLayoutValues.length; i++)
  1346. if(Integer.parseInt(keyboardLayoutValues[i].toString()) == mKeyboardLayout)
  1347. selectedLayoutIndex = i;
  1348. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  1349. builder.setTitle("Change keyboard layout")
  1350. .setCancelable(true)
  1351. .setNegativeButton(android.R.string.cancel, null)
  1352. .setSingleChoiceItems(R.array.keyboard_layouts, selectedLayoutIndex,
  1353. new DialogInterface.OnClickListener() {
  1354. public void onClick(DialogInterface di, int position) {
  1355. changePreference(PREF_KEYBOARD_LAYOUT, getResources().getTextArray(R.array.keyboard_layouts_values)[position].toString());
  1356. di.dismiss();
  1357. }
  1358. });
  1359. mOptionsDialog = builder.create();
  1360. Window window = mOptionsDialog.getWindow();
  1361. WindowManager.LayoutParams lp = window.getAttributes();
  1362. lp.token = mInputView.getWindowToken();
  1363. lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
  1364. window.setAttributes(lp);
  1365. window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
  1366. mOptionsDialog.show();
  1367. }
  1368. private void launchChooseDictionary() {
  1369. int selectedDictionaryIndex = -1;
  1370. for(int i = 0; i < mAvailableDictionaryValues.length; i++)
  1371. if(mDictionary.equals(mAvailableDictionaryValues[i]))
  1372. selectedDictionaryIndex = i;
  1373. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  1374. builder.setTitle("Change dictionary")
  1375. .setCancelable(true)
  1376. .setNegativeButton(android.R.string.cancel, null)
  1377. .setSingleChoiceItems(mAvailableDictionaries, selectedDictionaryIndex,
  1378. new DialogInterface.OnClickListener() {
  1379. public void onClick(DialogInterface di, int position) {
  1380. changePreference(PREF_DICTIONARY, mAvailableDictionaryValues[position].toString());
  1381. di.dismiss();
  1382. }
  1383. });
  1384. mOptionsDialog = builder.create();
  1385. Window window = mOptionsDialog.getWindow();
  1386. WindowManager.LayoutParams lp = window.getAttributes();
  1387. lp.token = mInputView.getWindowToken();
  1388. lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
  1389. window.setAttributes(lp);
  1390. window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
  1391. mOptionsDialog.show();
  1392. }
  1393. private void changePreference(String preference, String value) {
  1394. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(NorwegianIME.this);
  1395. SharedPreferences.Editor editor = sp.edit();
  1396. editor.putString(preference, value);
  1397. editor.commit();
  1398. onStartInputView(getCurrentInputEditorInfo(), true);
  1399. }
  1400. private void changePreference(String preference, boolean value) {
  1401. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(NorwegianIME.this);
  1402. SharedPreferences.Editor editor = sp.edit();
  1403. editor.putBoolean(preference, value);
  1404. editor.commit();
  1405. onStartInputView(getCurrentInputEditorInfo(), true);
  1406. }
  1407. private void changeKeyboardMode() {
  1408. mKeyboardSwitcher.toggleSymbols();
  1409. if (mCapsLock && mKeyboardSwitcher.isAlphabetMode()) {
  1410. ((NorwegianKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock);
  1411. }
  1412. updateShiftKeyState(getCurrentInputEditorInfo());
  1413. }
  1414. @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
  1415. super.dump(fd, fout, args);
  1416. final Printer p = new PrintWriterPrinter(fout);
  1417. p.println("NorwegianIME state :");
  1418. p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
  1419. p.println(" mCapsLock=" + mCapsLock);
  1420. p.println(" mComposing=" + mComposing.toString());
  1421. p.println(" mPredictionOn=" + mPredictionOn);
  1422. p.println(" mCorrectionMode=" + mCorrectionMode);
  1423. p.println(" mPredicting=" + mPredicting);
  1424. p.println(" mAutoCorrectOn=" + mAutoCorrectOn);
  1425. p.println(" mAutoSpace=" + mAutoSpace);
  1426. p.println(" mCompletionOn=" + mCompletionOn);
  1427. p.println(" TextEntryState.state=" + TextEntryState.getState());
  1428. p.println(" mSoundOn=" + mSoundOn);
  1429. p.println(" mVibrateOn=" + mVibrateOn);
  1430. p.println(" mKeyboardLayout=" + mKeyboardLayout);
  1431. }
  1432. // Characters per second measurement
  1433. private static final boolean PERF_DEBUG = false;
  1434. private long mLastCpsTime;
  1435. private static final int CPS_BUFFER_SIZE = 16;
  1436. private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
  1437. private int mCpsIndex;
  1438. private void measureCps() {
  1439. if (!NorwegianIME.PERF_DEBUG) return;
  1440. long now = System.currentTimeMillis();
  1441. if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
  1442. mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
  1443. mLastCpsTime = now;
  1444. mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
  1445. long total = 0;
  1446. for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
  1447. System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
  1448. }
  1449. class AutoDictionary extends ExpandableDictionary {
  1450. // If the user touches a typed word 2 times or more, it will become valid.
  1451. private int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED;
  1452. // If the user touches a typed word 5 times or more, it will be added to the user dict.
  1453. private int PROMOTION_THRESHOLD = 5 * FREQUENCY_FOR_PICKED;
  1454. public AutoDictionary(Context context) {
  1455. super(context);
  1456. this.loadSettings();
  1457. }
  1458. public void loadSettings() {
  1459. VALIDITY_THRESHOLD = mAutoDictionaryLimit * FREQUENCY_FOR_PICKED;
  1460. PROMOTION_THRESHOLD = mAutoDictionaryLimit * FREQUENCY_FOR_PICKED;
  1461. }
  1462. @Override
  1463. public boolean isValidWord(CharSequence word) {
  1464. if(!mAutoDictionaryCaseSensitive)
  1465. word = word.toString().toLowerCase();
  1466. final int frequency = getWordFrequency(word);
  1467. return frequency >= VALIDITY_THRESHOLD;
  1468. }
  1469. @Override
  1470. public void addWord(String word, int addFrequency) {
  1471. if(!mAutoDictionaryCaseSensitive)
  1472. word = word.toLowerCase();
  1473. final int length = word.length();
  1474. // Don't add very short or very long words.
  1475. if (length < 2 || length > getMaxWordLength()) return;
  1476. final int freq = getWordFrequency(word);
  1477. int newFreq = freq == -1 ? addFrequency : freq + addFrequency;
  1478. super.addWord(word, newFreq);
  1479. if (newFreq >= PROMOTION_THRESHOLD) {
  1480. NorwegianIME.this.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD);
  1481. }
  1482. }
  1483. }
  1484. private void createLetterSymbolArray() {
  1485. validKeyCodes = new ArrayList<Integer>();
  1486. letterSymbolArray = new HashMap<Integer, Integer>();
  1487. letterSymbolArray.put(97, 64);
  1488. letterSymbolArray.put(98, 59);
  1489. letterSymbolArray.put(99, 39);
  1490. letterSymbolArray.put(100, 36);
  1491. letterSymbolArray.put(101, 51);
  1492. letterSymbolArray.put(102, 37);
  1493. letterSymbolArray.put(103, 38);
  1494. letterSymbolArray.put(104, 42);
  1495. letterSymbolArray.put(105, 56);
  1496. letterSymbolArray.put(106, 45);
  1497. letterSymbolArray.put(107, 43);
  1498. letterSymbolArray.put(108, 40);
  1499. letterSymbolArray.put(109, 63);
  1500. letterSymbolArray.put(110, 47);
  1501. letterSymbolArray.put(111, 57);
  1502. letterSymbolArray.put(112, 48);
  1503. letterSymbolArray.put(113, 49);
  1504. letterSymbolArray.put(114, 52);
  1505. letterSymbolArray.put(115, 35);
  1506. letterSymbolArray.put(116, 53);
  1507. letterSymbolArray.put(117, 55);
  1508. letterSymbolArray.put(118, 58);
  1509. letterSymbolArray.put(119, 50);
  1510. letterSymbolArray.put(120, 34);
  1511. letterSymbolArray.put(121, 54);
  1512. letterSymbolArray.put(122, 33);
  1513. switch(mKeyboardLayout) {
  1514. case 1:
  1515. case 5:
  1516. case 6:
  1517. letterSymbolArray.put(230, 41);
  1518. letterSymbolArray.put(248, 95);
  1519. validKeyCodes.clear();
  1520. validKeyCodes.add(230);
  1521. validKeyCodes.add(248);
  1522. break;
  1523. case 3:
  1524. case 4:
  1525. letterSymbolArray.put(228, 95);
  1526. letterSymbolArray.put(246, 41);
  1527. validKeyCodes.clear();
  1528. validKeyCodes.add(228);
  1529. validKeyCodes.add(246);
  1530. break;
  1531. case 7:
  1532. letterSymbolArray.put(121, 33);
  1533. letterSymbolArray.put(122, 54);
  1534. letterSymbolArray.put(228, 95);
  1535. letterSymbolArray.put(246, 41);
  1536. validKeyCodes.clear();
  1537. validKeyCodes.add(228);
  1538. validKeyCodes.add(246);
  1539. break;
  1540. case 8:
  1541. letterSymbolArray.put(225, 49);
  1542. letterSymbolArray.put(353, 50);
  1543. letterSymbolArray.put(359, 54);
  1544. letterSymbolArray.put(248, 41);
  1545. letterSymbolArray.put(230, 95);
  1546. letterSymbolArray.put(382, 33);
  1547. letterSymbolArray.put(122, 34);
  1548. letterSymbolArray.put(269, 39);
  1549. letterSymbolArray.put(99, 58);
  1550. letterSymbolArray.put(118, 59);
  1551. letterSymbolArray.put(98, 47);
  1552. letterSymbolArray.put(110, 63);
  1553. validKeyCodes.clear();
  1554. validKeyCodes.add(225);
  1555. validKeyCodes.add(230);
  1556. validKeyCodes.add(248);
  1557. validKeyCodes.add(269);
  1558. validKeyCodes.add(353);
  1559. validKeyCodes.add(359);
  1560. validKeyCodes.add(382);
  1561. break;
  1562. default:
  1563. letterSymbolArray.put(230, 95);
  1564. letterSymbolArray.put(248, 41);
  1565. validKeyCodes.clear();
  1566. validKeyCodes.add(230);
  1567. validKeyCodes.add(248);
  1568. break;
  1569. }
  1570. }
  1571. }