/CircleIME/src/com/marvin/circleime/SoftKeyboard.java

http://eyes-free.googlecode.com/ · Java · 773 lines · 483 code · 102 blank · 188 comment · 155 complexity · dd1f59891313dc58efa8c9c899761922 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.marvin.circleime;
  17. import com.google.tts.TextToSpeechBeta;
  18. import android.content.res.Configuration;
  19. import android.inputmethodservice.InputMethodService;
  20. import android.inputmethodservice.Keyboard;
  21. import android.inputmethodservice.KeyboardView;
  22. import android.text.method.MetaKeyKeyListener;
  23. import android.util.Log;
  24. import android.view.KeyCharacterMap;
  25. import android.view.KeyEvent;
  26. import android.view.MotionEvent;
  27. import android.view.View;
  28. import android.view.ViewGroup.LayoutParams;
  29. import android.view.inputmethod.CompletionInfo;
  30. import android.view.inputmethod.EditorInfo;
  31. import android.view.inputmethod.InputConnection;
  32. import android.view.inputmethod.InputMethodManager;
  33. import android.widget.FrameLayout;
  34. import java.util.ArrayList;
  35. import java.util.List;
  36. /**
  37. * Example of writing an input method for a soft keyboard. This code is focused
  38. * on simplicity over completeness, so it should in no way be considered to be a
  39. * complete soft keyboard implementation. Its purpose is to provide a basic
  40. * example for how you would get started writing an input method, to be fleshed
  41. * out as appropriate.
  42. */
  43. public class SoftKeyboard extends InputMethodService implements
  44. KeyboardView.OnKeyboardActionListener {
  45. static final boolean DEBUG = false;
  46. /**
  47. * This boolean indicates the optional example code for performing
  48. * processing of hard keys in addition to regular text generation from
  49. * on-screen interaction. It would be used for input methods that perform
  50. * language translations (such as converting text entered on a QWERTY
  51. * keyboard to Chinese), but may not be used for input methods that are
  52. * primarily intended to be used for on-screen text entry.
  53. */
  54. static final boolean PROCESS_HARD_KEYS = true;
  55. private KeyboardView mInputView;
  56. private CandidateView mCandidateView;
  57. private CompletionInfo[] mCompletions;
  58. private StringBuilder mComposing = new StringBuilder();
  59. private boolean mPredictionOn;
  60. private boolean mCompletionOn;
  61. private int mLastDisplayWidth;
  62. private boolean mCapsLock;
  63. private long mLastShiftTime;
  64. private long mMetaState;
  65. private LatinKeyboard mSymbolsKeyboard;
  66. private LatinKeyboard mSymbolsShiftedKeyboard;
  67. private LatinKeyboard mQwertyKeyboard;
  68. private LatinKeyboard mCurKeyboard;
  69. private String mWordSeparators;
  70. public TextToSpeechBeta mTts;
  71. /**
  72. * Main initialization of the input method component. Be sure to call to
  73. * super class.
  74. */
  75. @Override
  76. public void onCreate() {
  77. super.onCreate();
  78. mWordSeparators = getResources().getString(R.string.word_separators);
  79. mTts = new TextToSpeechBeta(this, null);
  80. }
  81. @Override
  82. public void onDestroy() {
  83. if (mTts != null) {
  84. mTts.shutdown();
  85. }
  86. super.onDestroy();
  87. }
  88. /**
  89. * This is the point where you can do all of your UI initialization. It is
  90. * called after creation and any configuration change.
  91. */
  92. @Override
  93. public void onInitializeInterface() {
  94. if (mQwertyKeyboard != null) {
  95. // Configuration changes can happen after the keyboard gets
  96. // recreated,
  97. // so we need to be able to re-build the keyboards if the available
  98. // space has changed.
  99. int displayWidth = getMaxWidth();
  100. if (displayWidth == mLastDisplayWidth)
  101. return;
  102. mLastDisplayWidth = displayWidth;
  103. }
  104. mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
  105. mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
  106. mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
  107. }
  108. /**
  109. * Called by the framework when your view for creating input needs to be
  110. * generated. This will be called the first time your input method is
  111. * displayed, and every time it needs to be re-created such as due to a
  112. * configuration change.
  113. */
  114. @Override
  115. public View onCreateInputView() {
  116. mInputView = (KeyboardView) getLayoutInflater().inflate(R.layout.input, null);
  117. mInputView.setOnKeyboardActionListener(this);
  118. mInputView.setKeyboard(mQwertyKeyboard);
  119. return mInputView;
  120. }
  121. /**
  122. * Called by the framework when your view for showing candidates needs to be
  123. * generated, like {@link #onCreateInputView}.
  124. */
  125. @Override
  126. public View onCreateCandidatesView() {
  127. return null;
  128. }
  129. /**
  130. * This is the main point where we do our initialization of the input method
  131. * to begin operating on an application. At this point we have been bound to
  132. * the client, and are now receiving all of the detailed information about
  133. * the target of our edits.
  134. */
  135. @Override
  136. public void onStartInput(EditorInfo attribute, boolean restarting) {
  137. super.onStartInput(attribute, restarting);
  138. // Reset our state. We want to do this even if restarting, because
  139. // the underlying state of the text editor could have changed in any
  140. // way.
  141. mComposing.setLength(0);
  142. updateCandidates();
  143. if (!restarting) {
  144. // Clear shift states.
  145. mMetaState = 0;
  146. }
  147. mPredictionOn = false;
  148. mCompletionOn = false;
  149. mCompletions = null;
  150. // We are now going to initialize our state based on the type of
  151. // text being edited.
  152. switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
  153. case EditorInfo.TYPE_CLASS_NUMBER:
  154. case EditorInfo.TYPE_CLASS_DATETIME:
  155. // Numbers and dates default to the symbols keyboard, with
  156. // no extra features.
  157. mCurKeyboard = mSymbolsKeyboard;
  158. break;
  159. case EditorInfo.TYPE_CLASS_PHONE:
  160. // Phones will also default to the symbols keyboard, though
  161. // often you will want to have a dedicated phone keyboard.
  162. mCurKeyboard = mSymbolsKeyboard;
  163. break;
  164. case EditorInfo.TYPE_CLASS_TEXT:
  165. // This is general text editing. We will default to the
  166. // normal alphabetic keyboard, and assume that we should
  167. // be doing predictive text (showing candidates as the
  168. // user types).
  169. mCurKeyboard = mQwertyKeyboard;
  170. mPredictionOn = true;
  171. // We now look for a few special variations of text that will
  172. // modify our behavior.
  173. int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
  174. if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
  175. || variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
  176. // Do not display predictions / what the user is typing
  177. // when they are entering a password.
  178. mPredictionOn = false;
  179. }
  180. if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
  181. || variation == EditorInfo.TYPE_TEXT_VARIATION_URI
  182. || variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
  183. // Our predictions are not useful for e-mail addresses
  184. // or URIs.
  185. mPredictionOn = false;
  186. }
  187. if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
  188. // If this is an auto-complete text view, then our
  189. // predictions
  190. // will not be shown and instead we will allow the editor
  191. // to supply their own. We only show the editor's
  192. // candidates when in fullscreen mode, otherwise relying
  193. // own it displaying its own UI.
  194. mPredictionOn = false;
  195. mCompletionOn = isFullscreenMode();
  196. }
  197. // We also want to look at the current state of the editor
  198. // to decide whether our alphabetic keyboard should start out
  199. // shifted.
  200. updateShiftKeyState(attribute);
  201. break;
  202. default:
  203. // For all unknown input types, default to the alphabetic
  204. // keyboard with no special features.
  205. mCurKeyboard = mQwertyKeyboard;
  206. updateShiftKeyState(attribute);
  207. }
  208. // Update the label on the enter key, depending on what the application
  209. // says it will do.
  210. mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
  211. }
  212. /**
  213. * This is called when the user is done editing a field. We can use this to
  214. * reset our state.
  215. */
  216. @Override
  217. public void onFinishInput() {
  218. super.onFinishInput();
  219. // Clear current composing text and candidates.
  220. mComposing.setLength(0);
  221. updateCandidates();
  222. // We only hide the candidates window when finishing input on
  223. // a particular editor, to avoid popping the underlying application
  224. // up and down if the user is entering text into the bottom of
  225. // its window.
  226. setCandidatesViewShown(false);
  227. mCurKeyboard = mQwertyKeyboard;
  228. if (mInputView != null) {
  229. mInputView.closing();
  230. }
  231. }
  232. @Override
  233. public void onStartInputView(EditorInfo attribute, boolean restarting) {
  234. super.onStartInputView(attribute, restarting);
  235. // Apply the selected keyboard to the input view.
  236. mInputView.setKeyboard(mCurKeyboard);
  237. mInputView.closing();
  238. }
  239. /**
  240. * Deal with the editor reporting movement of its cursor.
  241. */
  242. @Override
  243. public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd,
  244. int candidatesStart, int candidatesEnd) {
  245. super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart,
  246. candidatesEnd);
  247. // If the current selection in the text view changes, we should
  248. // clear whatever candidate text we have.
  249. if (mComposing.length() > 0 && (newSelStart != candidatesEnd || newSelEnd != candidatesEnd)) {
  250. mComposing.setLength(0);
  251. updateCandidates();
  252. InputConnection ic = getCurrentInputConnection();
  253. if (ic != null) {
  254. ic.finishComposingText();
  255. }
  256. }
  257. }
  258. /**
  259. * This tells us about completions that the editor has determined based on
  260. * the current text in it. We want to use this in fullscreen mode to show
  261. * the completions ourself, since the editor can not be seen in that
  262. * situation.
  263. */
  264. @Override
  265. public void onDisplayCompletions(CompletionInfo[] completions) {
  266. if (mCompletionOn) {
  267. mCompletions = completions;
  268. if (completions == null) {
  269. setSuggestions(null, false, false);
  270. return;
  271. }
  272. List<String> stringList = new ArrayList<String>();
  273. for (int i = 0; i < (completions != null ? completions.length : 0); i++) {
  274. CompletionInfo ci = completions[i];
  275. if ((ci != null) && (ci.getText() != null))
  276. stringList.add(ci.getText().toString());
  277. }
  278. setSuggestions(stringList, true, true);
  279. }
  280. }
  281. /**
  282. * This translates incoming hard key events in to edit operations on an
  283. * InputConnection. It is only needed when using the PROCESS_HARD_KEYS
  284. * option.
  285. */
  286. private boolean translateKeyDown(int keyCode, KeyEvent event) {
  287. mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState, keyCode, event);
  288. int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));
  289. mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
  290. InputConnection ic = getCurrentInputConnection();
  291. if (c == 0 || ic == null) {
  292. return false;
  293. }
  294. boolean dead = false;
  295. if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
  296. dead = true;
  297. c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
  298. }
  299. if (mComposing.length() > 0) {
  300. char accent = mComposing.charAt(mComposing.length() - 1);
  301. int composed = KeyEvent.getDeadChar(accent, c);
  302. if (composed != 0) {
  303. c = composed;
  304. mComposing.setLength(mComposing.length() - 1);
  305. }
  306. }
  307. onKey(c, null);
  308. return true;
  309. }
  310. /**
  311. * Use this to monitor key events being delivered to the application. We get
  312. * first crack at them, and can either resume them or let them continue to
  313. * the app.
  314. */
  315. @Override
  316. public boolean onKeyDown(int keyCode, KeyEvent event) {
  317. switch (keyCode) {
  318. // Use search as an alternate enter key
  319. case KeyEvent.KEYCODE_SEARCH:
  320. this.sendDefaultEditorAction(false);
  321. return true;
  322. // TODO: Use menu as a "safer" way to dismiss the IME
  323. case KeyEvent.KEYCODE_MENU:
  324. Log.e("menu hit", "0");
  325. return true;
  326. case KeyEvent.KEYCODE_BACK:
  327. // The InputMethodService already takes care of the back
  328. // key for us, to dismiss the input method if it is shown.
  329. // However, our keyboard could be showing a pop-up window
  330. // that back should dismiss, so we first allow it to do that.
  331. if (event.getRepeatCount() == 0 && mInputView != null) {
  332. if (mInputView.handleBack()) {
  333. return true;
  334. }
  335. }
  336. break;
  337. case KeyEvent.KEYCODE_DEL:
  338. // Special handling of the delete key: if we currently are
  339. // composing text for the user, we want to modify that instead
  340. // of let the application to the delete itself.
  341. if (mComposing.length() > 0) {
  342. onKey(Keyboard.KEYCODE_DELETE, null);
  343. return true;
  344. }
  345. break;
  346. case KeyEvent.KEYCODE_ENTER:
  347. // Let the underlying text editor always handle these.
  348. return false;
  349. default:
  350. // For all other keys, if we want to do transformations on
  351. // text being entered with a hard keyboard, we need to process
  352. // it and do the appropriate action.
  353. if (PROCESS_HARD_KEYS) {
  354. if (keyCode == KeyEvent.KEYCODE_SPACE
  355. && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
  356. // A silly example: in our input method, Alt+Space
  357. // is a shortcut for 'android' in lower case.
  358. InputConnection ic = getCurrentInputConnection();
  359. if (ic != null) {
  360. // First, tell the editor that it is no longer in
  361. // the
  362. // shift state, since we are consuming this.
  363. ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
  364. keyDownUp(KeyEvent.KEYCODE_A);
  365. keyDownUp(KeyEvent.KEYCODE_N);
  366. keyDownUp(KeyEvent.KEYCODE_D);
  367. keyDownUp(KeyEvent.KEYCODE_R);
  368. keyDownUp(KeyEvent.KEYCODE_O);
  369. keyDownUp(KeyEvent.KEYCODE_I);
  370. keyDownUp(KeyEvent.KEYCODE_D);
  371. // And we consume this event.
  372. return true;
  373. }
  374. }
  375. if (mPredictionOn && translateKeyDown(keyCode, event)) {
  376. return true;
  377. }
  378. }
  379. }
  380. return super.onKeyDown(keyCode, event);
  381. }
  382. /**
  383. * Use this to monitor key events being delivered to the application. We get
  384. * first crack at them, and can either resume them or let them continue to
  385. * the app.
  386. */
  387. @Override
  388. public boolean onKeyUp(int keyCode, KeyEvent event) {
  389. // If we want to do transformations on text being entered with a hard
  390. // keyboard, we need to process the up events to update the meta key
  391. // state we are tracking.
  392. if (PROCESS_HARD_KEYS) {
  393. if (mPredictionOn) {
  394. mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState, keyCode, event);
  395. }
  396. }
  397. return super.onKeyUp(keyCode, event);
  398. }
  399. /**
  400. * Helper function to commit any text being composed in to the editor.
  401. */
  402. private void commitTyped(InputConnection inputConnection) {
  403. if (mComposing.length() > 0) {
  404. inputConnection.commitText(mComposing, mComposing.length());
  405. mComposing.setLength(0);
  406. updateCandidates();
  407. }
  408. }
  409. /**
  410. * Helper to update the shift state of our keyboard based on the initial
  411. * editor state.
  412. */
  413. private void updateShiftKeyState(EditorInfo attr) {
  414. if (attr != null && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {
  415. int caps = 0;
  416. EditorInfo ei = getCurrentInputEditorInfo();
  417. if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
  418. caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
  419. }
  420. mInputView.setShifted(mCapsLock || caps != 0);
  421. }
  422. }
  423. /**
  424. * Helper to determine if a given character code is alphabetic.
  425. */
  426. private boolean isAlphabet(int code) {
  427. if (Character.isLetter(code)) {
  428. return true;
  429. } else {
  430. return false;
  431. }
  432. }
  433. /**
  434. * Helper to send a key down / key up pair to the current editor.
  435. */
  436. private void keyDownUp(int keyEventCode) {
  437. getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
  438. getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
  439. }
  440. /**
  441. * Helper to send a character to the editor as raw key events.
  442. */
  443. private void sendKey(int keyCode) {
  444. switch (keyCode) {
  445. case '\n':
  446. keyDownUp(KeyEvent.KEYCODE_ENTER);
  447. break;
  448. default:
  449. if (keyCode >= '0' && keyCode <= '9') {
  450. keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
  451. } else {
  452. getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
  453. }
  454. break;
  455. }
  456. }
  457. // Implementation of KeyboardViewListener
  458. public void onKey(int primaryCode, int[] keyCodes) {
  459. if (isWordSeparator(primaryCode)) {
  460. // Handle separator
  461. if (mComposing.length() > 0) {
  462. commitTyped(getCurrentInputConnection());
  463. }
  464. sendKey(primaryCode);
  465. updateShiftKeyState(getCurrentInputEditorInfo());
  466. } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
  467. handleBackspace();
  468. } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
  469. handleShift();
  470. } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
  471. handleClose();
  472. return;
  473. } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mInputView != null) {
  474. Keyboard current = mInputView.getKeyboard();
  475. if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
  476. current = mQwertyKeyboard;
  477. } else {
  478. current = mSymbolsKeyboard;
  479. }
  480. mInputView.setKeyboard(current);
  481. if (current == mSymbolsKeyboard) {
  482. current.setShifted(false);
  483. }
  484. } else {
  485. handleCharacter(primaryCode, keyCodes);
  486. }
  487. }
  488. public void onText(CharSequence text) {
  489. InputConnection ic = getCurrentInputConnection();
  490. if (ic == null)
  491. return;
  492. ic.beginBatchEdit();
  493. if (mComposing.length() > 0) {
  494. commitTyped(ic);
  495. }
  496. ic.commitText(text, 0);
  497. ic.endBatchEdit();
  498. updateShiftKeyState(getCurrentInputEditorInfo());
  499. }
  500. /**
  501. * Update the list of available candidates from the current composing text.
  502. * This will need to be filled in by however you are determining candidates.
  503. */
  504. private void updateCandidates() {
  505. if (!mCompletionOn) {
  506. if (mComposing.length() > 0) {
  507. ArrayList<String> list = new ArrayList<String>();
  508. list.add(mComposing.toString());
  509. setSuggestions(list, true, true);
  510. } else {
  511. setSuggestions(null, false, false);
  512. }
  513. }
  514. }
  515. public void setSuggestions(List<String> suggestions, boolean completions, boolean typedWordValid) {
  516. if (suggestions != null && suggestions.size() > 0) {
  517. setCandidatesViewShown(true);
  518. } else if (isExtractViewShown()) {
  519. setCandidatesViewShown(true);
  520. }
  521. if (mCandidateView != null) {
  522. mCandidateView.setSuggestions(suggestions, completions, typedWordValid);
  523. }
  524. }
  525. public void handleBackspace() {
  526. final int length = mComposing.length();
  527. if (length > 1) {
  528. mComposing.delete(length - 1, length);
  529. getCurrentInputConnection().setComposingText(mComposing, 1);
  530. updateCandidates();
  531. } else if (length > 0) {
  532. mComposing.setLength(0);
  533. getCurrentInputConnection().commitText("", 0);
  534. updateCandidates();
  535. } else {
  536. keyDownUp(KeyEvent.KEYCODE_DEL);
  537. }
  538. updateShiftKeyState(getCurrentInputEditorInfo());
  539. }
  540. private void handleShift() {
  541. if (mInputView == null) {
  542. return;
  543. }
  544. Keyboard currentKeyboard = mInputView.getKeyboard();
  545. if (mQwertyKeyboard == currentKeyboard) {
  546. // Alphabet keyboard
  547. checkToggleCapsLock();
  548. mInputView.setShifted(mCapsLock || !mInputView.isShifted());
  549. } else if (currentKeyboard == mSymbolsKeyboard) {
  550. mSymbolsKeyboard.setShifted(true);
  551. mInputView.setKeyboard(mSymbolsShiftedKeyboard);
  552. mSymbolsShiftedKeyboard.setShifted(true);
  553. } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
  554. mSymbolsShiftedKeyboard.setShifted(false);
  555. mInputView.setKeyboard(mSymbolsKeyboard);
  556. mSymbolsKeyboard.setShifted(false);
  557. }
  558. }
  559. private void handleCharacter(int primaryCode, int[] keyCodes) {
  560. if (isInputViewShown()) {
  561. if (mInputView.isShifted()) {
  562. primaryCode = Character.toUpperCase(primaryCode);
  563. }
  564. }
  565. if (isAlphabet(primaryCode) && mPredictionOn) {
  566. mComposing.append((char) primaryCode);
  567. getCurrentInputConnection().setComposingText(mComposing, 1);
  568. updateShiftKeyState(getCurrentInputEditorInfo());
  569. updateCandidates();
  570. } else {
  571. getCurrentInputConnection().commitText(String.valueOf((char) primaryCode), 1);
  572. }
  573. }
  574. private void handleClose() {
  575. commitTyped(getCurrentInputConnection());
  576. requestHideSelf(0);
  577. mInputView.closing();
  578. }
  579. private void checkToggleCapsLock() {
  580. long now = System.currentTimeMillis();
  581. if (mLastShiftTime + 800 > now) {
  582. mCapsLock = !mCapsLock;
  583. mLastShiftTime = 0;
  584. } else {
  585. mLastShiftTime = now;
  586. }
  587. }
  588. private String getWordSeparators() {
  589. return mWordSeparators;
  590. }
  591. public boolean isWordSeparator(int code) {
  592. String separators = getWordSeparators();
  593. return separators.contains(String.valueOf((char) code));
  594. }
  595. public void pickDefaultCandidate() {
  596. pickSuggestionManually(0);
  597. }
  598. public void pickSuggestionManually(int index) {
  599. if (mCompletionOn && mCompletions != null && index >= 0 && index < mCompletions.length) {
  600. CompletionInfo ci = mCompletions[index];
  601. getCurrentInputConnection().commitCompletion(ci);
  602. if (mCandidateView != null) {
  603. mCandidateView.clear();
  604. }
  605. updateShiftKeyState(getCurrentInputEditorInfo());
  606. } else if (mComposing.length() > 0) {
  607. // If we were generating candidate suggestions for the current
  608. // text, we would commit one of them here. But for this sample,
  609. // we will just commit the current text.
  610. commitTyped(getCurrentInputConnection());
  611. }
  612. }
  613. public void swipeRight() {
  614. if (mCompletionOn) {
  615. pickDefaultCandidate();
  616. }
  617. }
  618. public void swipeLeft() {
  619. handleBackspace();
  620. }
  621. public void swipeDown() {
  622. handleClose();
  623. }
  624. public void swipeUp() {
  625. }
  626. public void onPress(int primaryCode) {
  627. }
  628. public void onRelease(int primaryCode) {
  629. }
  630. /*
  631. public void onComputeInsets(Insets outInsets) {
  632. View decor = getWindow().getWindow().getDecorView();
  633. outInsets.visibleTopInsets = decor.getHeight(); //0;
  634. outInsets.contentTopInsets = 0; //decor.getHeight();
  635. outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
  636. }
  637. */
  638. public boolean isLandscape() {
  639. if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
  640. return true;
  641. }
  642. return false;
  643. }
  644. @Override
  645. public boolean onEvaluateFullscreenMode(){
  646. return true;
  647. }
  648. @Override
  649. public void onUpdateExtractingVisibility (EditorInfo ei){
  650. ei.imeOptions = EditorInfo.TYPE_NULL;
  651. // ei.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;
  652. setExtractViewShown(false);
  653. }
  654. @Override
  655. public void onUpdateExtractingViews(EditorInfo ei){
  656. ei.imeOptions = EditorInfo.TYPE_NULL;
  657. // EditorInfo.IME_FLAG_NO_EXTRACT_UI;
  658. setExtractViewShown(false);
  659. }
  660. @Override
  661. public View onCreateExtractTextView (){
  662. return null;
  663. //View extractTextView = super.onCreateExtractTextView();
  664. //extractTextView.setVisibility(View.GONE);
  665. //return extractTextView;
  666. }
  667. @Override
  668. public void onWindowHidden(){
  669. this.stopSelf();
  670. }
  671. }