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