OpenWnnEN.java revision 053d50935e0e311286543bd7c535ae2c863c0de8
1/* 2 * Copyright (C) 2008,2009 OMRON SOFTWARE Co., Ltd. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package jp.co.omronsoft.openwnn; 18 19import jp.co.omronsoft.openwnn.EN.*; 20import android.content.SharedPreferences; 21import android.content.Context; 22import android.content.res.Configuration; 23import android.inputmethodservice.InputMethodService; 24import android.os.Handler; 25import android.preference.PreferenceManager; 26import android.provider.Settings; 27import android.text.SpannableStringBuilder; 28import android.text.Spanned; 29import android.text.method.MetaKeyKeyListener; 30import android.text.style.BackgroundColorSpan; 31import android.text.style.CharacterStyle; 32import android.text.style.UnderlineSpan; 33import android.util.Log; 34import android.view.KeyCharacterMap; 35import android.view.KeyEvent; 36import android.view.inputmethod.EditorInfo; 37 38/** 39 * OpenWnn English IME 40 * 41 * @author Copyright (C) 2009, OMRON SOFTWARE CO., LTD. All Rights Reserved. 42 */ 43public class OpenWnnEN extends OpenWnn { 44 private static final char[] SPACE = {' '}; 45 private static final CharacterStyle SPAN_BGCOLOR_HL = new BackgroundColorSpan(0xFF8888FF); 46 private static final CharacterStyle SPAN_UNDERLINE = new UnderlineSpan(); 47 private static final int PRIVATE_AREA_CODE = 61184; 48 private static final int MOD = 3; 49 50 /** Spannable string for the composing text */ 51 protected SpannableStringBuilder mDisplayText; 52 53 /** Handler for drawing the candidates view */ 54 private Handler mDelayUpdateHandler; 55 /** Characters treated as a separator */ 56 private String mWordSeparators; 57 /** Previous event's code */ 58 private int mPreviousEventCode; 59 60 private WnnWord[] mUserDictionaryWords = null; 61 62 private OpenWnnEngineEN mConverterEN; 63 private SymbolList mSymbolList; 64 private boolean mSymbolMode; 65 private boolean mOptPrediction; 66 private boolean mOptSpellCorrection; 67 private boolean mOptLearning; 68 private int mHardShift; 69 private int mHardAlt; 70 71 /** Instance of this service */ 72 private static OpenWnnEN mSelf = null; 73 74 /** Shift lock toggle definition */ 75 private static final int[] mShiftKeyToggle = {0, MetaKeyKeyListener.META_SHIFT_ON, MetaKeyKeyListener.META_CAP_LOCKED}; 76 /** Alt lock toggle definition */ 77 private static final int[] mAltKeyToggle = {0, MetaKeyKeyListener.META_ALT_ON, MetaKeyKeyListener.META_ALT_LOCKED}; 78 /** Auto caps mode */ 79 private boolean mAutoCaps = false; 80 81 /** 82 * Constructor 83 */ 84 public OpenWnnEN() { 85 super(); 86 mSelf = this; 87 88 /* used by OpenWnn */ 89 mComposingText = new ComposingText(); 90 mCandidatesViewManager = new TextCandidatesViewManagerEN(300); 91 mInputViewManager = new DefaultSoftKeyboardEN(); 92 mConverterEN = new OpenWnnEngineEN("/data/data/jp.co.omronsoft.openwnn/writableEN.dic"); 93 mConverter = mConverterEN; 94 mSymbolList = null; 95 96 /* etc */ 97 mDisplayText = new SpannableStringBuilder(); 98 mAutoHideMode = false; 99 mDelayUpdateHandler = new Handler(); 100 mSymbolMode = false; 101 mOptPrediction = true; 102 mOptSpellCorrection = true; 103 mOptLearning = true; 104 } 105 106 /** 107 * Constructor 108 * 109 * @param context The context 110 */ 111 public OpenWnnEN(Context context) { 112 this(); 113 attachBaseContext(context); 114 } 115 /** 116 * Get the instance of this service. 117 * <br> 118 * Before using this method, the constructor of this service must be invoked. 119 */ 120 public static OpenWnnEN getInstance() { 121 return mSelf; 122 } 123 124 /** 125 * Insert a character into the composing text. 126 * 127 * @param chars a character 128 */ 129 private void insertCharToComposingText(char[] chars) { 130 StrSegment seg = new StrSegment(chars); 131 132 if (chars[0] == SPACE[0] || chars[0] == '\u0009') { 133 /* if the character is a space, commit the composing text */ 134 commitText(1); 135 commitText(seg.string); 136 mComposingText.clear(); 137 } else if (mWordSeparators.contains(seg.string)) { 138 /* if the character is a separator, remove an auto-inserted space and commit the composing text. */ 139 if (mPreviousEventCode == OpenWnnEvent.SELECT_CANDIDATE) { 140 mInputConnection.deleteSurroundingText(1, 0); 141 } 142 commitText(1); 143 commitText(seg.string); 144 mComposingText.clear(); 145 } else { 146 mComposingText.insertStrSegment(0, 1, seg); 147 updateComposingText(1); 148 } 149 } 150 151 /** 152 * Insert a character into the composing text. 153 * 154 * @param charCode a character code 155 * @return true if success; false if an error occurs. 156 */ 157 private boolean insertCharToComposingText(int charCode) { 158 if (charCode == 0) { 159 return false; 160 } 161 insertCharToComposingText(Character.toChars(charCode)); 162 return true; 163 } 164 165 166 /** 167 * Get the shift key state from the editor. 168 * 169 * @param editor editor 170 * 171 * @return state id of the shift key (0:off, 1:on) 172 */ 173 protected int getShiftKeyState(EditorInfo editor) { 174 return (getCurrentInputConnection().getCursorCapsMode(editor.inputType) == 0) ? 0 : 1; 175 } 176 177 /** 178 * Set the mode of the symbol list. 179 * @param mode <code>SymbolList.SYMBOL_ENGLISH</code> or <code>null</code> 180 */ 181 private void setSymbolMode(String mode) { 182 if (mode != null) { 183 mDelayUpdateHandler.removeCallbacks(updatePredictionRunnable); 184 mSymbolMode = true; 185 mSymbolList.setDictionary(mode); 186 mConverter = mSymbolList; 187 } else { 188 if (!mSymbolMode) { 189 return; 190 } 191 mDelayUpdateHandler.removeCallbacks(updatePredictionRunnable); 192 mSymbolMode = false; 193 mConverter = mConverterEN; 194 } 195 } 196 197 /*********************************************************************** 198 * InputMethodServer 199 ***********************************************************************/ 200 /** @see jp.co.omronsoft.openwnn.OpenWnn#onCreate */ 201 @Override public void onCreate() { 202 super.onCreate(); 203 mWordSeparators = getResources().getString(R.string.en_word_separators); 204 205 if (mSymbolList == null) { 206 mSymbolList = new SymbolList(this, SymbolList.LANG_EN); 207 } 208 } 209 210 /** @see jp.co.omronsoft.openwnn.OpenWnn#onStartInputView */ 211 @Override public void onStartInputView(EditorInfo attribute, boolean restarting) { 212 super.onStartInputView(attribute, restarting); 213 214 /* initialize views */ 215 mCandidatesViewManager.clearCandidates(); 216 217 mHardShift = 0; 218 mHardAlt = 0; 219 /* auto caps mode */ 220 try { 221 mAutoCaps = (Settings.System.getInt(getContentResolver(), Settings.System.TEXT_AUTO_CAPS) != 0); 222 } catch (android.provider.Settings.SettingNotFoundException ex) { 223 mAutoCaps = false; 224 } 225 226 /* load preferences */ 227 SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); 228 229 /* set TextCandidatesViewManager's option */ 230 ((TextCandidatesViewManagerEN)mCandidatesViewManager).setAutoHide(true); 231 232 /* display status icon */ 233 showStatusIcon(R.drawable.immodeic_half_alphabet); 234 235 /* set prediction & spell correction mode */ 236 mOptPrediction = pref.getBoolean("opt_en_prediction", true); 237 mOptSpellCorrection = pref.getBoolean("opt_en_spell_correction", true); 238 mOptLearning = pref.getBoolean("opt_en_enable_learning", true); 239 240 /* prediction on/off */ 241 switch (attribute.inputType & EditorInfo.TYPE_MASK_VARIATION) { 242 case EditorInfo.TYPE_TEXT_VARIATION_PASSWORD: 243 mOptLearning = false; 244 mOptPrediction = false; 245 break; 246 default: 247 break; 248 } 249 250 /* set engine's mode */ 251 if (mOptSpellCorrection) { 252 mConverterEN.setDictionary(OpenWnnEngineEN.DICT_FOR_CORRECT_MISTYPE); 253 } else { 254 mConverterEN.setDictionary(OpenWnnEngineEN.DICT_DEFAULT); 255 } 256 257 /* doesn't learn any word if it is not prediction mode */ 258 if (!mOptPrediction) { 259 mOptLearning = false; 260 } 261 262 263 if (mComposingText != null) { 264 mComposingText.clear(); 265 } 266 } 267 268 /** @see jp.co.omronsoft.openwnn.OpenWnn#onComputeInsets */ 269 @Override public void onComputeInsets(InputMethodService.Insets outInsets) { 270 if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) { 271 outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_FRAME; 272 } else { 273 super.onComputeInsets(outInsets); 274 } 275 } 276 277 /** @see jp.co.omronsoft.openwnn.OpenWnn#isFullscreenMode */ 278 @Override public boolean isFullscreenMode() { 279 boolean ret; 280 if (mInputViewManager == null) { 281 ret = (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL); 282 } else { 283 ret = false; 284 } 285 return ret; 286 } 287 288 /** @see jp.co.omronsoft.openwnn.OpenWnn#onUpdateSelection */ 289 @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd, 290 int newSelStart, int newSelEnd, int candidatesStart, 291 int candidatesEnd) { 292 if (mComposingText.size(1) != 0) { 293 updateComposingText(1); 294 } 295 } 296 297 /** @see jp.co.omronsoft.openwnn.OpenWnn#onConfigurationChanged */ 298 @Override public void onConfigurationChanged(Configuration newConfig) { 299 try { 300 super.onConfigurationChanged(newConfig); 301 if (mInputConnection != null) { 302 updateComposingText(1); 303 } 304 } catch (Exception ex) { 305 } 306 } 307 308 /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvaluateFullscreenMode */ 309 @Override public boolean onEvaluateFullscreenMode() { 310 return false; 311 } 312 313 /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvaluateInputViewShown */ 314 @Override public boolean onEvaluateInputViewShown() { 315 return true; 316 } 317 318 /*********************************************************************** 319 * OpenWnn 320 ***********************************************************************/ 321 /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvent */ 322 @Override synchronized public boolean onEvent(OpenWnnEvent ev) { 323 /* handling events which are valid when InputConnection is not active. */ 324 switch (ev.code) { 325 326 case OpenWnnEvent.INITIALIZE_LEARNING_DICTIONARY: 327 return mConverterEN.initializeDictionary( WnnEngine.DICTIONARY_TYPE_LEARN ); 328 329 case OpenWnnEvent.INITIALIZE_USER_DICTIONARY: 330 return mConverterEN.initializeDictionary( WnnEngine.DICTIONARY_TYPE_USER ); 331 332 case OpenWnnEvent.LIST_WORDS_IN_USER_DICTIONARY: 333 mUserDictionaryWords = mConverterEN.getUserDictionaryWords( ); 334 return true; 335 336 case OpenWnnEvent.GET_WORD: 337 if( mUserDictionaryWords != null ) { 338 ev.word = mUserDictionaryWords[ 0 ]; 339 for( int i = 0 ; i < mUserDictionaryWords.length-1 ; i++ ) { 340 mUserDictionaryWords[ i ] = mUserDictionaryWords[ i + 1 ]; 341 } 342 mUserDictionaryWords[ mUserDictionaryWords.length-1 ] = null; 343 if( mUserDictionaryWords[ 0 ] == null ) { 344 mUserDictionaryWords = null; 345 } 346 return true; 347 } 348 break; 349 350 case OpenWnnEvent.ADD_WORD: 351 mConverterEN.addWord(ev.word); 352 return true; 353 354 case OpenWnnEvent.DELETE_WORD: 355 mConverterEN.deleteWord(ev.word); 356 return true; 357 358 case OpenWnnEvent.CHANGE_MODE: 359 return false; 360 361 default: 362 break; 363 } 364 365 dismissPopupKeyboard(); 366 367 if (mDirectInputMode) { 368 return false; 369 } 370 371 if (ev.code == OpenWnnEvent.LIST_CANDIDATES_FULL) { 372 mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_FULL); 373 return true; 374 } 375 376 boolean ret = false; 377 switch (ev.code) { 378 case OpenWnnEvent.INPUT_CHAR: 379 EditorInfo edit = getCurrentInputEditorInfo(); 380 if( edit.inputType == EditorInfo.TYPE_CLASS_PHONE){ 381 commitText(new String(ev.chars)); 382 }else{ 383 setSymbolMode(null); 384 insertCharToComposingText(ev.chars); 385 ret = true; 386 mPreviousEventCode = ev.code; 387 } 388 break; 389 390 case OpenWnnEvent.INPUT_KEY: 391 int keyCode = ev.keyEvent.getKeyCode(); 392 /* update shift/alt state */ 393 switch (keyCode) { 394 case KeyEvent.KEYCODE_ALT_LEFT: 395 case KeyEvent.KEYCODE_ALT_RIGHT: 396 if (ev.keyEvent.getRepeatCount() == 0) { 397 if (++mHardAlt > 2) { mHardAlt = 0; } 398 } 399 updateMetaKeyStateDisplay(); 400 return true; 401 402 case KeyEvent.KEYCODE_SHIFT_LEFT: 403 case KeyEvent.KEYCODE_SHIFT_RIGHT: 404 if (ev.keyEvent.getRepeatCount() == 0) { 405 if (++mHardShift > 2) { mHardShift = 0; } 406 } 407 updateMetaKeyStateDisplay(); 408 return true; 409 } 410 setSymbolMode(null); 411 updateComposingText(1); 412 /* handle other key event */ 413 ret = processKeyEvent(ev.keyEvent); 414 mPreviousEventCode = ev.code; 415 break; 416 417 case OpenWnnEvent.INPUT_SOFT_KEY: 418 setSymbolMode(null); 419 updateComposingText(1); 420 ret = processKeyEvent(ev.keyEvent); 421 if (!ret) { 422 mInputConnection.sendKeyEvent(ev.keyEvent); 423 mInputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, ev.keyEvent.getKeyCode())); 424 ret = true; 425 } 426 mPreviousEventCode = ev.code; 427 break; 428 429 case OpenWnnEvent.SELECT_CANDIDATE: 430 if (mSymbolMode) { 431 commitText(ev.word, false); 432 } else { 433 if (mWordSeparators.contains(ev.word.candidate) && 434 mPreviousEventCode == OpenWnnEvent.SELECT_CANDIDATE) { 435 mInputConnection.deleteSurroundingText(1, 0); 436 } 437 commitText(ev.word, true); 438 } 439 mComposingText.clear(); 440 mPreviousEventCode = ev.code; 441 updateComposingText(1); 442 break; 443 444 case OpenWnnEvent.LIST_SYMBOLS: 445 commitText(1); 446 mComposingText.clear(); 447 setSymbolMode(SymbolList.SYMBOL_ENGLISH); 448 updateComposingText(1); 449 break; 450 451 default: 452 break; 453 } 454 455 if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) { 456 mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL); 457 } 458 459 return ret; 460 } 461 462 /*********************************************************************** 463 * OpenWnnEN 464 ***********************************************************************/ 465 /** 466 * Handling KeyEvent 467 * <br> 468 * This method is called from <code>onEvent()</code>. 469 * 470 * @param ev a key event 471 */ 472 private boolean processKeyEvent(KeyEvent ev) { 473 474 int key = ev.getKeyCode(); 475 EditorInfo edit = getCurrentInputEditorInfo(); 476 /* keys which produce a glyph */ 477 if (ev.isPrintingKey()) { 478 /* do nothing if the character is not able to display or the character is dead key */ 479 if ((mHardShift > 0 && mHardAlt > 0) || 480 (ev.isAltPressed() == true && ev.isShiftPressed() == true)) { 481 int charCode = ev.getUnicodeChar(MetaKeyKeyListener.META_SHIFT_ON | MetaKeyKeyListener.META_ALT_ON); 482 if (charCode == 0 || (charCode & KeyCharacterMap.COMBINING_ACCENT) != 0 || charCode == PRIVATE_AREA_CODE) { 483 if (mHardAlt == 1) { 484 mHardAlt = 0; 485 } 486 if (mHardShift == 1) { 487 mHardShift = 0; 488 } 489 updateMetaKeyStateDisplay(); 490 return true; 491 } 492 } 493 494 /* get the key character */ 495 if (mHardShift== 0 && mHardAlt == 0) { 496 /* no meta key is locked */ 497 int shift = (mAutoCaps) ? getShiftKeyState(edit) : 0; 498 if (shift != mHardShift && (key >= KeyEvent.KEYCODE_A && key <= KeyEvent.KEYCODE_Z)) { 499 /* handling auto caps for a alphabet character */ 500 insertCharToComposingText(ev.getUnicodeChar(MetaKeyKeyListener.META_SHIFT_ON)); 501 } else { 502 insertCharToComposingText(ev.getUnicodeChar()); 503 } 504 } else { 505 insertCharToComposingText(ev.getUnicodeChar(mShiftKeyToggle[mHardShift] 506 | mAltKeyToggle[mHardAlt])); 507 /* back to 0 (off) if 1 (on/not locked) */ 508 if (mHardAlt == 1) { 509 mHardAlt = 0; 510 } 511 if (mHardShift == 1) { 512 mHardShift = 0; 513 } 514 updateMetaKeyStateDisplay(); 515 } 516 517 if (edit.inputType == EditorInfo.TYPE_CLASS_PHONE) { 518 commitText(1); 519 mComposingText.clear(); 520 return true; 521 } 522 return true; 523 524 } else if (key == KeyEvent.KEYCODE_SPACE) { 525 if (ev.isAltPressed()) { 526 /* display the symbol list (G1 specific. same as KEYCODE_SYM) */ 527 commitText(1); 528 mComposingText.clear(); 529 setSymbolMode(SymbolList.SYMBOL_ENGLISH); 530 updateComposingText(1); 531 mHardAlt = 0; 532 updateMetaKeyStateDisplay(); 533 } else { 534 insertCharToComposingText(SPACE); 535 } 536 return true; 537 } else if (key == KeyEvent.KEYCODE_SYM) { 538 /* display the symbol list */ 539 commitText(1); 540 mComposingText.clear(); 541 setSymbolMode(SymbolList.SYMBOL_ENGLISH); 542 updateComposingText(1); 543 mHardAlt = 0; 544 updateMetaKeyStateDisplay(); 545 } 546 547 548 /* Functional key */ 549 if (mComposingText.size(1) > 0) { 550 switch (key) { 551 case KeyEvent.KEYCODE_DEL: 552 mComposingText.delete(1, false); 553 updateComposingText(1); 554 return true; 555 556 case KeyEvent.KEYCODE_BACK: 557 if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) { 558 mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL); 559 } else { 560 mComposingText.clear(); 561 updateComposingText(1); 562 } 563 return true; 564 565 case KeyEvent.KEYCODE_DPAD_LEFT: 566 mComposingText.moveCursor(1, -1); 567 updateComposingText(1); 568 return true; 569 570 case KeyEvent.KEYCODE_DPAD_RIGHT: 571 mComposingText.moveCursor(1, 1); 572 updateComposingText(1); 573 return true; 574 575 case KeyEvent.KEYCODE_ENTER: 576 case KeyEvent.KEYCODE_DPAD_CENTER: 577 commitText(1); 578 mComposingText.clear(); 579 return true; 580 581 default: 582 break; 583 } 584 } 585 586 return false; 587 } 588 589 /** 590 * Runnable for a thread getting and displaying candidates. 591 */ 592 private final Runnable updatePredictionRunnable = new Runnable() { 593 public void run() { 594 int candidates = 0; 595 if (mConverter != null) { 596 597 candidates = mConverter.predict(mComposingText, 0, -1); 598 } 599 600 if (candidates > 0) { 601 mCandidatesViewManager.displayCandidates(mConverter); 602 } else { 603 mCandidatesViewManager.clearCandidates(); 604 } 605 } 606 }; 607 608 /** 609 * Update the composing text. 610 * 611 * @param layer <code>mComposingText</code>'s layer to display 612 */ 613 private void updateComposingText(int layer) { 614 /* update the candidates view */ 615 if (!mOptPrediction) { 616 commitText(1); 617 mComposingText.clear(); 618 if (mSymbolMode) { 619 mDelayUpdateHandler.removeCallbacks(updatePredictionRunnable); 620 mDelayUpdateHandler.postDelayed(updatePredictionRunnable, 0); 621 } 622 } else { 623 if (mComposingText.size(1) != 0) { 624 mDelayUpdateHandler.removeCallbacks(updatePredictionRunnable); 625 mDelayUpdateHandler.postDelayed(updatePredictionRunnable, 250); 626 } else { 627 mDelayUpdateHandler.removeCallbacks(updatePredictionRunnable); 628 mDelayUpdateHandler.postDelayed(updatePredictionRunnable, 0); 629 } 630 631 /* notice to the input view */ 632 this.mInputViewManager.onUpdateState(this); 633 634 /* set the candidates view to the normal size */ 635 if (mCandidatesViewManager.getViewType() != CandidatesViewManager.VIEW_TYPE_NORMAL) { 636 mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL); 637 } 638 /* set the text for displaying as the composing text */ 639 SpannableStringBuilder disp = mDisplayText; 640 disp.clear(); 641 disp.insert(0, mComposingText.toString(layer)); 642 643 /* add decoration to the text */ 644 int start = 0; 645 int cursor = mComposingText.getCursor(layer); 646 if (disp.length() != 0) { 647 disp.setSpan(SPAN_UNDERLINE, start, disp.length(), 648 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 649 } 650 /* update the composing text on the EditView */ 651 mInputConnection.setComposingText(disp, cursor); 652 } 653 } 654 655 /** 656 * Commit the composing text. 657 * 658 * @param layer <code>mComposingText</code>'s layer to commit. 659 */ 660 private void commitText(int layer) { 661 String tmp = mComposingText.toString(layer); 662 663 if (mOptLearning && mConverter != null && tmp.length() > 0) { 664 WnnWord word = new WnnWord(tmp, tmp); 665 mConverter.learn(word); 666 } 667 668 mInputConnection.commitText(tmp, tmp.length()); 669 mCandidatesViewManager.clearCandidates(); 670 } 671 672 /** 673 * Commit a word 674 * 675 * @param word a word to commit 676 * @param withSpace append a space after the word if <code>true</code> 677 */ 678 private void commitText(WnnWord word, boolean withSpace) { 679 680 if (mOptLearning && mConverter != null) { 681 mConverter.learn(word); 682 } 683 684 mInputConnection.commitText(word.candidate, word.candidate.length()); 685 686 if (withSpace) { 687 commitText(" "); 688 } 689 } 690 691 /** 692 * Commit a string 693 * <br> 694 * The string is not registered into the learning dictionary. 695 * 696 * @param str a string to commit 697 */ 698 private void commitText(String str) { 699 mInputConnection.commitText(str, str.length()); 700 mCandidatesViewManager.clearCandidates(); 701 } 702 703 /** 704 * Dismiss the pop-up keyboard 705 */ 706 protected void dismissPopupKeyboard() { 707 DefaultSoftKeyboardEN kbd = (DefaultSoftKeyboardEN)mInputViewManager; 708 if (kbd != null) { 709 kbd.dismissPopupKeyboard(); 710 } 711 } 712 713 /** 714 * Display current meta-key state. 715 */ 716 private void updateMetaKeyStateDisplay() { 717 } 718} 719 720 721 722 723 724