• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package jp.co.omronsoft.openwnn;
18 
19 import jp.co.omronsoft.openwnn.EN.*;
20 import android.content.SharedPreferences;
21 import android.content.Context;
22 import android.content.res.Configuration;
23 import android.os.Message;
24 import android.os.Handler;
25 import android.preference.PreferenceManager;
26 import android.text.SpannableStringBuilder;
27 import android.text.Spanned;
28 import android.text.method.MetaKeyKeyListener;
29 import android.text.style.BackgroundColorSpan;
30 import android.text.style.CharacterStyle;
31 import android.text.style.ForegroundColorSpan;
32 import android.text.style.UnderlineSpan;
33 import android.util.Log;
34 import android.view.KeyCharacterMap;
35 import android.view.KeyEvent;
36 import android.view.MotionEvent;
37 import android.view.View;
38 import android.view.inputmethod.EditorInfo;
39 
40 /**
41  * The OpenWnn English IME class.
42  *
43  * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
44  */
45 public class OpenWnnEN extends OpenWnn {
46     /** A space character */
47     private static final char[] SPACE = {' '};
48 
49     /** Character style of underline */
50     private static final CharacterStyle SPAN_UNDERLINE   = new UnderlineSpan();
51     /** Highlight color style for the selected string  */
52     private static final CharacterStyle SPAN_EXACT_BGCOLOR_HL     = new BackgroundColorSpan(0xFF66CDAA);
53     /** Highlight color style for the composing text */
54     private static final CharacterStyle SPAN_REMAIN_BGCOLOR_HL    = new BackgroundColorSpan(0xFFF0FFFF);
55     /** Highlight text color */
56     private static final CharacterStyle SPAN_TEXTCOLOR  = new ForegroundColorSpan(0xFF000000);
57 
58     /** A private area code(ALT+SHIFT+X) to be ignore (G1 specific). */
59     private static final int PRIVATE_AREA_CODE = 61184;
60     /** Never move cursor in to the composing text (adapting to IMF's specification change) */
61     private static final boolean FIX_CURSOR_TEXT_END = true;
62 
63     /** Spannable string for the composing text */
64     protected SpannableStringBuilder mDisplayText;
65 
66     /** Characters treated as a separator */
67     private String mWordSeparators;
68     /** Previous event's code */
69     private int mPreviousEventCode;
70 
71     /** Array of words from the user dictionary */
72     private WnnWord[] mUserDictionaryWords = null;
73 
74     /** The converter for English prediction/spell correction */
75     private OpenWnnEngineEN mConverterEN;
76     /** The symbol list generator */
77     private SymbolList mSymbolList;
78     /** Whether it is displaying symbol list */
79     private boolean mSymbolMode;
80     /** Whether prediction is enabled */
81     private boolean mOptPrediction;
82     /** Whether spell correction is enabled */
83     private boolean mOptSpellCorrection;
84     /** Whether learning is enabled */
85     private boolean mOptLearning;
86 
87     /** SHIFT key state */
88     private int mHardShift;
89     /** SHIFT key state (pressing) */
90     private boolean mShiftPressing;
91     /** ALT key state */
92     private int mHardAlt;
93     /** ALT key state (pressing) */
94     private boolean mAltPressing;
95 
96     /** Instance of this service */
97     private static OpenWnnEN mSelf = null;
98 
99     /** Shift lock toggle definition */
100     private static final int[] mShiftKeyToggle = {0, MetaKeyKeyListener.META_SHIFT_ON, MetaKeyKeyListener.META_CAP_LOCKED};
101     /** ALT lock toggle definition */
102     private static final int[] mAltKeyToggle = {0, MetaKeyKeyListener.META_ALT_ON, MetaKeyKeyListener.META_ALT_LOCKED};
103     /** Auto caps mode */
104     private boolean mAutoCaps = false;
105 
106     /** Whether dismissing the keyboard when the enter key is pressed */
107     private boolean mEnableAutoHideKeyboard = true;
108 
109     /** Tutorial */
110     private TutorialEN mTutorial;
111 
112     /** Whether tutorial mode or not */
113     private boolean mEnableTutorial;
114 
115     /** Message for {@code mHandler} (execute prediction) */
116     private static final int MSG_PREDICTION = 0;
117 
118     /** Message for {@code mHandler} (execute tutorial) */
119     private static final int MSG_START_TUTORIAL = 1;
120 
121     /** Message for {@code mHandler} (close) */
122     private static final int MSG_CLOSE = 2;
123 
124     /** Delay time(msec.) to start prediction after key input when the candidates view is not shown. */
125     private static final int PREDICTION_DELAY_MS_1ST = 200;
126 
127     /** Delay time(msec.) to start prediction after key input when the candidates view is shown. */
128     private static final int PREDICTION_DELAY_MS_SHOWING_CANDIDATE = 200;
129 
130     /** {@code Handler} for drawing candidates/displaying tutorial */
131     Handler mHandler = new Handler() {
132             @Override public void handleMessage(Message msg) {
133                 switch (msg.what) {
134                 case MSG_PREDICTION:
135                     updatePrediction();
136                     break;
137                 case MSG_START_TUTORIAL:
138                     if (mTutorial == null) {
139                         if (isInputViewShown()) {
140                             DefaultSoftKeyboardEN inputManager = ((DefaultSoftKeyboardEN) mInputViewManager);
141                             View v = inputManager.getKeyboardView();
142                             mTutorial = new TutorialEN(OpenWnnEN.this, v, inputManager);
143 
144                             mTutorial.start();
145                         } else {
146                             /* Try again soon if the view is not yet showing */
147                             sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
148                         }
149                     }
150                     break;
151                 case MSG_CLOSE:
152                     if (mConverterEN != null) mConverterEN.close();
153                     if (mSymbolList != null) mSymbolList.close();
154                     break;
155                 }
156             }
157         };
158 
159     /**
160      * Constructor
161      */
OpenWnnEN()162     public OpenWnnEN() {
163         super();
164         mSelf = this;
165 
166         /* used by OpenWnn */
167         mComposingText = new ComposingText();
168         mCandidatesViewManager = new TextCandidatesViewManager(-1);
169         mInputViewManager = new DefaultSoftKeyboardEN();
170         mConverterEN = new OpenWnnEngineEN("/data/data/jp.co.omronsoft.openwnn/writableEN.dic");
171         mConverter = mConverterEN;
172         mSymbolList = null;
173 
174         /* etc */
175         mDisplayText = new SpannableStringBuilder();
176         mAutoHideMode = false;
177         mSymbolMode = false;
178         mOptPrediction = true;
179         mOptSpellCorrection = true;
180         mOptLearning = true;
181     }
182 
183     /**
184      * Constructor
185      *
186      * @param context       The context
187      */
OpenWnnEN(Context context)188     public OpenWnnEN(Context context) {
189         this();
190         attachBaseContext(context);
191     }
192     /**
193      * Get the instance of this service.
194      * <br>
195      * Before using this method, the constructor of this service must be invoked.
196      *
197      * @return      The instance of this object
198      */
getInstance()199     public static OpenWnnEN getInstance() {
200         return mSelf;
201     }
202 
203     /**
204      * Insert a character into the composing text.
205      *
206      * @param chars     A array of character
207      */
insertCharToComposingText(char[] chars)208     private void insertCharToComposingText(char[] chars) {
209         StrSegment seg = new StrSegment(chars);
210 
211         if (chars[0] == SPACE[0] || chars[0] == '\u0009') {
212             /* if the character is a space, commit the composing text */
213             commitText(1);
214             commitText(seg.string);
215             mComposingText.clear();
216         } else if (mWordSeparators.contains(seg.string)) {
217             /* if the character is a separator, remove an auto-inserted space and commit the composing text. */
218             if (mPreviousEventCode == OpenWnnEvent.SELECT_CANDIDATE) {
219                 mInputConnection.deleteSurroundingText(1, 0);
220             }
221             commitText(1);
222             commitText(seg.string);
223             mComposingText.clear();
224         } else {
225             mComposingText.insertStrSegment(0, 1, seg);
226             updateComposingText(1);
227         }
228     }
229 
230     /**
231      * Insert a character into the composing text.
232      *
233      * @param charCode      A character code
234      * @return              {@code true} if success; {@code false} if an error occurs.
235      */
insertCharToComposingText(int charCode)236     private boolean insertCharToComposingText(int charCode) {
237         if (charCode == 0) {
238             return false;
239         }
240         insertCharToComposingText(Character.toChars(charCode));
241         return true;
242     }
243 
244     /**
245      * Get the shift key state from the editor.
246      *
247      * @param editor    Editor
248      *
249      * @return          State ID of the shift key (0:off, 1:on)
250      */
getShiftKeyState(EditorInfo editor)251     protected int getShiftKeyState(EditorInfo editor) {
252         return (getCurrentInputConnection().getCursorCapsMode(editor.inputType) == 0) ? 0 : 1;
253     }
254 
255     /**
256      * Set the mode of the symbol list.
257      *
258      * @param mode      {@code SymbolList.SYMBOL_ENGLISH} or {@code null}.
259      */
setSymbolMode(String mode)260     private void setSymbolMode(String mode) {
261         if (mode != null) {
262             mHandler.removeMessages(MSG_PREDICTION);
263             mSymbolMode = true;
264             mSymbolList.setDictionary(mode);
265             mConverter = mSymbolList;
266         } else {
267             if (!mSymbolMode) {
268                 return;
269             }
270             mHandler.removeMessages(MSG_PREDICTION);
271             mSymbolMode = false;
272             mConverter = mConverterEN;
273         }
274     }
275 
276     /***********************************************************************
277      * InputMethodServer
278      ***********************************************************************/
279     /** @see jp.co.omronsoft.openwnn.OpenWnn#onCreate */
onCreate()280     @Override public void onCreate() {
281         super.onCreate();
282         mWordSeparators = getResources().getString(R.string.en_word_separators);
283 
284         if (mSymbolList == null) {
285             mSymbolList = new SymbolList(this, SymbolList.LANG_EN);
286         }
287     }
288 
289     /** @see jp.co.omronsoft.openwnn.OpenWnn#onCreateInputView */
onCreateInputView()290     @Override public View onCreateInputView() {
291         int hiddenState = getResources().getConfiguration().hardKeyboardHidden;
292         boolean hidden = (hiddenState == Configuration.HARDKEYBOARDHIDDEN_YES);
293         ((DefaultSoftKeyboardEN) mInputViewManager).setHardKeyboardHidden(hidden);
294         mEnableTutorial = hidden;
295 
296         return super.onCreateInputView();
297     }
298 
299     /** @see jp.co.omronsoft.openwnn.OpenWnn#onStartInputView */
onStartInputView(EditorInfo attribute, boolean restarting)300     @Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
301         super.onStartInputView(attribute, restarting);
302 
303         /* initialize views */
304         mCandidatesViewManager.clearCandidates();
305         mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_CLOSE);
306 
307         mHardShift = 0;
308         mHardAlt   = 0;
309         updateMetaKeyStateDisplay();
310 
311         /* load preferences */
312         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
313 
314         /* auto caps mode */
315         mAutoCaps = pref.getBoolean("auto_caps", true);
316 
317         /* set TextCandidatesViewManager's option */
318         ((TextCandidatesViewManager)mCandidatesViewManager).setAutoHide(true);
319 
320         /* display status icon */
321         showStatusIcon(R.drawable.immodeic_half_alphabet);
322 
323         if (mComposingText != null) {
324             mComposingText.clear();
325         }
326         /* initialize the engine's state */
327         fitInputType(pref, attribute);
328 
329         ((DefaultSoftKeyboard) mInputViewManager).resetCurrentKeyboard();
330     }
331 
332     /** @see jp.co.omronsoft.openwnn.OpenWnn#hideWindow */
hideWindow()333     @Override public void hideWindow() {
334         mComposingText.clear();
335         mInputViewManager.onUpdateState(this);
336         mHandler.removeMessages(MSG_START_TUTORIAL);
337         mInputViewManager.closing();
338         if (mTutorial != null) {
339             mTutorial.close();
340             mTutorial = null;
341         }
342 
343         super.hideWindow();
344     }
345 
346     /** @see jp.co.omronsoft.openwnn.OpenWnn#onUpdateSelection */
onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd)347     @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd,
348             int newSelStart, int newSelEnd, int candidatesStart,
349             int candidatesEnd) {
350 
351         boolean isNotComposing = ((candidatesStart < 0) && (candidatesEnd < 0));
352         if (isNotComposing) {
353             mComposingText.clear();
354             updateComposingText(1);
355         } else {
356             if (mComposingText.size(1) != 0) {
357                 updateComposingText(1);
358             }
359         }
360     }
361 
362     /** @see jp.co.omronsoft.openwnn.OpenWnn#onConfigurationChanged */
onConfigurationChanged(Configuration newConfig)363     @Override public void onConfigurationChanged(Configuration newConfig) {
364         try {
365             super.onConfigurationChanged(newConfig);
366             if (mInputConnection != null) {
367                 updateComposingText(1);
368             }
369             /* Hardware keyboard */
370             int hiddenState = newConfig.hardKeyboardHidden;
371             boolean hidden = (hiddenState == Configuration.HARDKEYBOARDHIDDEN_YES);
372             mEnableTutorial = hidden;
373         } catch (Exception ex) {
374         }
375     }
376 
377     /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvaluateFullscreenMode */
onEvaluateFullscreenMode()378     @Override public boolean onEvaluateFullscreenMode() {
379         return false;
380     }
381 
382     /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvaluateInputViewShown */
onEvaluateInputViewShown()383     @Override public boolean onEvaluateInputViewShown() {
384         return true;
385     }
386 
387     /***********************************************************************
388      * OpenWnn
389      ***********************************************************************/
390     /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvent */
onEvent(OpenWnnEvent ev)391     @Override synchronized public boolean onEvent(OpenWnnEvent ev) {
392         /* handling events which are valid when InputConnection is not active. */
393         switch (ev.code) {
394 
395         case OpenWnnEvent.KEYUP:
396             onKeyUpEvent(ev.keyEvent);
397             return true;
398 
399         case OpenWnnEvent.INITIALIZE_LEARNING_DICTIONARY:
400             return mConverterEN.initializeDictionary( WnnEngine.DICTIONARY_TYPE_LEARN );
401 
402         case OpenWnnEvent.INITIALIZE_USER_DICTIONARY:
403             return mConverterEN.initializeDictionary( WnnEngine.DICTIONARY_TYPE_USER );
404 
405         case OpenWnnEvent.LIST_WORDS_IN_USER_DICTIONARY:
406             mUserDictionaryWords = mConverterEN.getUserDictionaryWords( );
407             return true;
408 
409         case OpenWnnEvent.GET_WORD:
410             if( mUserDictionaryWords != null ) {
411                 ev.word = mUserDictionaryWords[ 0 ];
412                 for( int i = 0 ; i < mUserDictionaryWords.length-1 ; i++ ) {
413                     mUserDictionaryWords[ i ] = mUserDictionaryWords[ i + 1 ];
414                 }
415                 mUserDictionaryWords[ mUserDictionaryWords.length-1 ] = null;
416                 if( mUserDictionaryWords[ 0 ] == null ) {
417                     mUserDictionaryWords = null;
418                 }
419                 return true;
420             }
421             break;
422 
423         case OpenWnnEvent.ADD_WORD:
424             mConverterEN.addWord(ev.word);
425             return true;
426 
427         case OpenWnnEvent.DELETE_WORD:
428             mConverterEN.deleteWord(ev.word);
429             return true;
430 
431         case OpenWnnEvent.CHANGE_MODE:
432             return false;
433 
434         case OpenWnnEvent.UPDATE_CANDIDATE:
435             updateComposingText(ComposingText.LAYER1);
436             return true;
437 
438         case OpenWnnEvent.CHANGE_INPUT_VIEW:
439             setInputView(onCreateInputView());
440             return true;
441 
442         case OpenWnnEvent.CANDIDATE_VIEW_TOUCH:
443             boolean ret;
444                 ret = ((TextCandidatesViewManager)mCandidatesViewManager).onTouchSync();
445             return ret;
446 
447         default:
448             break;
449         }
450 
451         dismissPopupKeyboard();
452         KeyEvent keyEvent = ev.keyEvent;
453         int keyCode = 0;
454         if (keyEvent != null) {
455             keyCode = keyEvent.getKeyCode();
456         }
457         if (mDirectInputMode) {
458             if (ev.code == OpenWnnEvent.INPUT_SOFT_KEY && mInputConnection != null) {
459                 mInputConnection.sendKeyEvent(keyEvent);
460                 mInputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
461                                                            keyEvent.getKeyCode()));
462             }
463             return false;
464         }
465 
466         if (ev.code == OpenWnnEvent.LIST_CANDIDATES_FULL) {
467             mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_FULL);
468             return true;
469         } else if (ev.code == OpenWnnEvent.LIST_CANDIDATES_NORMAL) {
470             mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
471             return true;
472         }
473 
474         boolean ret = false;
475         switch (ev.code) {
476         case OpenWnnEvent.INPUT_CHAR:
477              ((TextCandidatesViewManager)mCandidatesViewManager).setAutoHide(false);
478             EditorInfo edit = getCurrentInputEditorInfo();
479             if( edit.inputType == EditorInfo.TYPE_CLASS_PHONE){
480                 commitText(new String(ev.chars));
481             }else{
482                 setSymbolMode(null);
483                 insertCharToComposingText(ev.chars);
484                 ret = true;
485                 mPreviousEventCode = ev.code;
486             }
487             break;
488 
489         case OpenWnnEvent.INPUT_KEY:
490             keyCode = ev.keyEvent.getKeyCode();
491             /* update shift/alt state */
492             switch (keyCode) {
493             case KeyEvent.KEYCODE_ALT_LEFT:
494             case KeyEvent.KEYCODE_ALT_RIGHT:
495                 if (ev.keyEvent.getRepeatCount() == 0) {
496                     if (++mHardAlt > 2) { mHardAlt = 0; }
497                 }
498                 mAltPressing   = true;
499                 updateMetaKeyStateDisplay();
500                 return true;
501 
502             case KeyEvent.KEYCODE_SHIFT_LEFT:
503             case KeyEvent.KEYCODE_SHIFT_RIGHT:
504                 if (ev.keyEvent.getRepeatCount() == 0) {
505                     if (++mHardShift > 2) { mHardShift = 0; }
506                 }
507                 mShiftPressing = true;
508                 updateMetaKeyStateDisplay();
509                 return true;
510             }
511             setSymbolMode(null);
512             updateComposingText(1);
513             /* handle other key event */
514             ret = processKeyEvent(ev.keyEvent);
515             mPreviousEventCode = ev.code;
516             break;
517 
518         case OpenWnnEvent.INPUT_SOFT_KEY:
519             setSymbolMode(null);
520             updateComposingText(1);
521             ret = processKeyEvent(ev.keyEvent);
522             if (!ret) {
523                 mInputConnection.sendKeyEvent(ev.keyEvent);
524                 mInputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, ev.keyEvent.getKeyCode()));
525                 ret = true;
526             }
527             mPreviousEventCode = ev.code;
528             break;
529 
530         case OpenWnnEvent.SELECT_CANDIDATE:
531             if (mSymbolMode) {
532                 commitText(ev.word, false);
533             } else {
534                 if (mWordSeparators.contains(ev.word.candidate) &&
535                     mPreviousEventCode == OpenWnnEvent.SELECT_CANDIDATE) {
536                     mInputConnection.deleteSurroundingText(1, 0);
537                 }
538                 commitText(ev.word, true);
539             }
540             mComposingText.clear();
541             mPreviousEventCode = ev.code;
542             updateComposingText(1);
543             break;
544 
545         case OpenWnnEvent.LIST_SYMBOLS:
546             commitText(1);
547             mComposingText.clear();
548             setSymbolMode(SymbolList.SYMBOL_ENGLISH);
549             updateComposingText(1);
550             break;
551 
552         default:
553             break;
554         }
555 
556         if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) {
557         	mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
558         }
559 
560         return ret;
561     }
562 
563     /***********************************************************************
564      * OpenWnnEN
565      ***********************************************************************/
566     /**
567      * Handling KeyEvent
568      * <br>
569      * This method is called from {@link #onEvent()}.
570      *
571      * @param ev   A key event
572      * @return      {@code true} if the event is processed in this method; {@code false} if the event is not processed in this method
573      */
processKeyEvent(KeyEvent ev)574     private boolean processKeyEvent(KeyEvent ev) {
575 
576         int key = ev.getKeyCode();
577         EditorInfo edit = getCurrentInputEditorInfo();
578         /* keys which produce a glyph */
579         if (ev.isPrintingKey()) {
580             /* do nothing if the character is not able to display or the character is dead key */
581             if ((mHardShift > 0 && mHardAlt > 0) || (ev.isAltPressed() && ev.isShiftPressed())) {
582                 int charCode = ev.getUnicodeChar(MetaKeyKeyListener.META_SHIFT_ON | MetaKeyKeyListener.META_ALT_ON);
583                 if (charCode == 0 || (charCode & KeyCharacterMap.COMBINING_ACCENT) != 0 || charCode == PRIVATE_AREA_CODE) {
584                     if(mHardShift == 1){
585                         mShiftPressing = false;
586                     }
587                     if(mHardAlt == 1){
588                         mAltPressing   = false;
589                     }
590                     if(!ev.isAltPressed()){
591                         if (mHardAlt == 1) {
592                             mHardAlt = 0;
593                         }
594                     }
595                     if(!ev.isShiftPressed()){
596                         if (mHardShift == 1) {
597                             mHardShift = 0;
598                         }
599                     }
600                     if(!ev.isShiftPressed() && !ev.isAltPressed()){
601                         updateMetaKeyStateDisplay();
602                     }
603                     return true;
604                 }
605             }
606 
607             ((TextCandidatesViewManager)mCandidatesViewManager).setAutoHide(false);
608 
609             /* get the key character */
610             if (mHardShift== 0  && mHardAlt == 0) {
611                 /* no meta key is locked */
612                 int shift = (mAutoCaps) ? getShiftKeyState(edit) : 0;
613                 if (shift != mHardShift && (key >= KeyEvent.KEYCODE_A && key <= KeyEvent.KEYCODE_Z)) {
614                     /* handling auto caps for a alphabet character */
615                     insertCharToComposingText(ev.getUnicodeChar(MetaKeyKeyListener.META_SHIFT_ON));
616                 } else {
617                     insertCharToComposingText(ev.getUnicodeChar());
618                 }
619             } else {
620                 insertCharToComposingText(ev.getUnicodeChar(mShiftKeyToggle[mHardShift]
621                                                             | mAltKeyToggle[mHardAlt]));
622                 if(mHardShift == 1){
623                     mShiftPressing = false;
624                 }
625                 if(mHardAlt == 1){
626                     mAltPressing   = false;
627                 }
628                 /* back to 0 (off) if 1 (on/not locked) */
629                 if(!ev.isAltPressed()){
630                     if (mHardAlt == 1) {
631                         mHardAlt = 0;
632                     }
633                 }
634                 if(!ev.isShiftPressed()){
635                     if (mHardShift == 1) {
636                         mHardShift = 0;
637                     }
638                 }
639                 if(!ev.isShiftPressed() && !ev.isAltPressed()){
640                     updateMetaKeyStateDisplay();
641                 }
642             }
643 
644             if (edit.inputType == EditorInfo.TYPE_CLASS_PHONE) {
645                 commitText(1);
646                 mComposingText.clear();
647                 return true;
648             }
649             return true;
650 
651         } else if (key == KeyEvent.KEYCODE_SPACE) {
652             if (ev.isAltPressed()) {
653                 /* display the symbol list (G1 specific. same as KEYCODE_SYM) */
654                 commitText(1);
655                 mComposingText.clear();
656                 setSymbolMode(SymbolList.SYMBOL_ENGLISH);
657                 updateComposingText(1);
658                 mHardAlt = 0;
659                 updateMetaKeyStateDisplay();
660             } else {
661                 insertCharToComposingText(SPACE);
662             }
663             return true;
664         } else if (key == KeyEvent.KEYCODE_SYM) {
665             /* display the symbol list */
666             commitText(1);
667             mComposingText.clear();
668             setSymbolMode(SymbolList.SYMBOL_ENGLISH);
669             updateComposingText(1);
670             mHardAlt = 0;
671             updateMetaKeyStateDisplay();
672         }
673 
674 
675         /* Functional key */
676         if (mComposingText.size(1) > 0) {
677             switch (key) {
678             case KeyEvent.KEYCODE_DEL:
679                 mComposingText.delete(1, false);
680                 updateComposingText(1);
681                 return true;
682 
683             case KeyEvent.KEYCODE_BACK:
684                 if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) {
685                     mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
686                 } else {
687                     mComposingText.clear();
688                     updateComposingText(1);
689                 }
690                 return true;
691 
692             case KeyEvent.KEYCODE_DPAD_LEFT:
693                 mComposingText.moveCursor(1, -1);
694                 updateComposingText(1);
695                 return true;
696 
697             case KeyEvent.KEYCODE_DPAD_RIGHT:
698                 mComposingText.moveCursor(1, 1);
699                 updateComposingText(1);
700                 return true;
701 
702             case KeyEvent.KEYCODE_ENTER:
703             case KeyEvent.KEYCODE_DPAD_CENTER:
704                 commitText(1);
705                 mComposingText.clear();
706                 if (mEnableAutoHideKeyboard) {
707                     mInputViewManager.closing();
708                     requestHideSelf(0);
709                 }
710                 return true;
711 
712             default:
713                 break;
714             }
715         } else {
716             /* if there is no composing string. */
717             if (mCandidatesViewManager.getCurrentView().isShown()) {
718             	if (key == KeyEvent.KEYCODE_BACK) {
719             		if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) {
720             			mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
721             		} else {
722             			mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_CLOSE);
723             		}
724             		return true;
725             	}
726             } else {
727                 switch (key) {
728                 case KeyEvent.KEYCODE_DPAD_CENTER:
729                 case KeyEvent.KEYCODE_ENTER:
730                     if (mEnableAutoHideKeyboard) {
731                         mInputViewManager.closing();
732                         requestHideSelf(0);
733                         return true;
734                     }
735                     break;
736                 case KeyEvent.KEYCODE_BACK:
737                     /*
738                      * If 'BACK' key is pressed when the SW-keyboard is shown
739                      * and the candidates view is not shown, dismiss the SW-keyboard.
740                      */
741                     if (isInputViewShown()) {
742                         mInputViewManager.closing();
743                         requestHideSelf(0);
744                         return true;
745                     }
746                     break;
747                 default:
748                     break;
749                 }
750             }
751         }
752 
753         return false;
754     }
755 
756     /**
757      * Thread for updating the candidates view
758      */
updatePrediction()759     private void updatePrediction() {
760         int candidates = 0;
761         if (mConverter != null) {
762             /* normal prediction */
763             candidates = mConverter.predict(mComposingText, 0, -1);
764         }
765         /* update the candidates view */
766         if (candidates > 0) {
767             mCandidatesViewManager.displayCandidates(mConverter);
768         } else {
769             mCandidatesViewManager.clearCandidates();
770         }
771     }
772 
773     /**
774      * Update the composing text.
775      *
776      * @param layer  {@link mComposingText}'s layer to display
777      */
updateComposingText(int layer)778     private void updateComposingText(int layer) {
779         /* update the candidates view */
780         if (!mOptPrediction) {
781             commitText(1);
782             mComposingText.clear();
783             if (mSymbolMode) {
784                 mHandler.removeMessages(MSG_PREDICTION);
785                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PREDICTION), 0);
786             }
787         } else {
788             if (mComposingText.size(1) != 0) {
789                 mHandler.removeMessages(MSG_PREDICTION);
790                 if (mCandidatesViewManager.getCurrentView().isShown()) {
791                     mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PREDICTION),
792                                                 PREDICTION_DELAY_MS_SHOWING_CANDIDATE);
793                 } else {
794                     mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PREDICTION),
795                                                 PREDICTION_DELAY_MS_1ST);
796                 }
797             } else {
798                 mHandler.removeMessages(MSG_PREDICTION);
799                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PREDICTION), 0);
800             }
801 
802             /* notice to the input view */
803             this.mInputViewManager.onUpdateState(this);
804 
805             /* set the text for displaying as the composing text */
806             SpannableStringBuilder disp = mDisplayText;
807             disp.clear();
808             disp.insert(0, mComposingText.toString(layer));
809 
810             /* add decoration to the text */
811             int cursor = mComposingText.getCursor(layer);
812             if (disp.length() != 0) {
813                 if (cursor > 0 && cursor < disp.length()) {
814                     disp.setSpan(SPAN_EXACT_BGCOLOR_HL, 0, cursor,
815                             Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
816                 }
817                 if (cursor < disp.length()) {
818                     mDisplayText.setSpan(SPAN_REMAIN_BGCOLOR_HL, cursor, disp.length(),
819                             Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
820                     mDisplayText.setSpan(SPAN_TEXTCOLOR, 0, disp.length(),
821                             Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
822                 }
823 
824                 disp.setSpan(SPAN_UNDERLINE, 0, disp.length(),
825                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
826             }
827 
828             int displayCursor = cursor;
829             if (FIX_CURSOR_TEXT_END) {
830                 displayCursor = (cursor == 0) ?  0 : 1;
831             }
832             /* update the composing text on the EditView */
833             mInputConnection.setComposingText(disp, displayCursor);
834         }
835     }
836 
837     /**
838      * Commit the composing text.
839      *
840      * @param layer  {@link mComposingText}'s layer to commit.
841      */
commitText(int layer)842     private void commitText(int layer) {
843         String tmp = mComposingText.toString(layer);
844 
845         if (mOptLearning && mConverter != null && tmp.length() > 0) {
846             WnnWord word = new WnnWord(tmp, tmp);
847             mConverter.learn(word);
848         }
849 
850         mInputConnection.commitText(tmp, (FIX_CURSOR_TEXT_END ? 1 : tmp.length()));
851         mCandidatesViewManager.clearCandidates();
852     }
853 
854     /**
855      * Commit a word
856      *
857      * @param word          A word to commit
858      * @param withSpace     Append a space after the word if {@code true}.
859      */
commitText(WnnWord word, boolean withSpace)860     private void commitText(WnnWord word, boolean withSpace) {
861 
862         if (mOptLearning && mConverter != null) {
863             mConverter.learn(word);
864         }
865 
866         mInputConnection.commitText(word.candidate, (FIX_CURSOR_TEXT_END ? 1 : word.candidate.length()));
867 
868         if (withSpace) {
869             commitText(" ");
870         }
871     }
872 
873     /**
874      * Commit a string
875      * <br>
876      * The string is not registered into the learning dictionary.
877      *
878      * @param str  A string to commit
879      */
commitText(String str)880     private void commitText(String str) {
881         mInputConnection.commitText(str, (FIX_CURSOR_TEXT_END ? 1 : str.length()));
882         mCandidatesViewManager.clearCandidates();
883     }
884 
885     /**
886      * Dismiss the pop-up keyboard
887      */
dismissPopupKeyboard()888     protected void dismissPopupKeyboard() {
889         DefaultSoftKeyboardEN kbd = (DefaultSoftKeyboardEN)mInputViewManager;
890         if (kbd != null) {
891             kbd.dismissPopupKeyboard();
892         }
893     }
894 
895     /**
896      * Display current meta-key state.
897      */
updateMetaKeyStateDisplay()898     private void updateMetaKeyStateDisplay() {
899         int mode = 0;
900         if(mHardShift == 0 && mHardAlt == 0){
901             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_OFF;
902         }else if(mHardShift == 1 && mHardAlt == 0){
903             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_ON_ALT_OFF;
904         }else if(mHardShift == 2  && mHardAlt == 0){
905             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_LOCK_ALT_OFF;
906         }else if(mHardShift == 0 && mHardAlt == 1){
907             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_ON;
908         }else if(mHardShift == 0 && mHardAlt == 2){
909             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_LOCK;
910         }else if(mHardShift == 1 && mHardAlt == 1){
911             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_ON_ALT_ON;
912         }else if(mHardShift == 1 && mHardAlt == 2){
913             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_ON_ALT_LOCK;
914         }else if(mHardShift == 2 && mHardAlt == 1){
915             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_LOCK_ALT_ON;
916         }else if(mHardShift == 2 && mHardAlt == 2){
917             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_LOCK_ALT_LOCK;
918         }else{
919             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_OFF;
920         }
921 
922         ((DefaultSoftKeyboard) mInputViewManager).updateIndicator(mode);
923     }
924 
925     /**
926      * Handling KeyEvent(KEYUP)
927      * <br>
928      * This method is called from {@link #onEvent()}.
929      *
930      * @param ev   An up key event
931      */
onKeyUpEvent(KeyEvent ev)932     private void onKeyUpEvent(KeyEvent ev) {
933         int key = ev.getKeyCode();
934         if(!mShiftPressing){
935             if(key == KeyEvent.KEYCODE_SHIFT_LEFT || key == KeyEvent.KEYCODE_SHIFT_RIGHT){
936                 mHardShift = 0;
937                 mShiftPressing = true;
938                 updateMetaKeyStateDisplay();
939             }
940         }
941         if(!mAltPressing ){
942             if(key == KeyEvent.KEYCODE_ALT_LEFT || key == KeyEvent.KEYCODE_ALT_RIGHT){
943                 mHardAlt = 0;
944                 mAltPressing   = true;
945                 updateMetaKeyStateDisplay();
946             }
947         }
948     }
949     /**
950      * Fits an editor info.
951      *
952      * @param preferences  The preference data.
953      * @param info          The editor info.
954      */
fitInputType(SharedPreferences preference, EditorInfo info)955     private void fitInputType(SharedPreferences preference, EditorInfo info) {
956         if (info.inputType == EditorInfo.TYPE_NULL) {
957             mDirectInputMode = true;
958             return;
959         }
960 
961         mEnableAutoHideKeyboard = false;
962 
963         /* set prediction & spell correction mode */
964         mOptPrediction      = preference.getBoolean("opt_en_prediction", true);
965         mOptSpellCorrection = preference.getBoolean("opt_en_spell_correction", true);
966         mOptLearning        = preference.getBoolean("opt_en_enable_learning", true);
967 
968         /* prediction on/off */
969         switch (info.inputType & EditorInfo.TYPE_MASK_CLASS) {
970         case EditorInfo.TYPE_CLASS_NUMBER:
971         case EditorInfo.TYPE_CLASS_DATETIME:
972         case EditorInfo.TYPE_CLASS_PHONE:
973             mOptPrediction = false;
974             mOptLearning = false;
975             break;
976 
977         case EditorInfo.TYPE_CLASS_TEXT:
978             switch (info.inputType & EditorInfo.TYPE_MASK_VARIATION) {
979             case EditorInfo.TYPE_TEXT_VARIATION_PASSWORD:
980                 mEnableAutoHideKeyboard = true;
981                 mOptLearning = false;
982                 mOptPrediction = false;
983                 break;
984 
985             case EditorInfo.TYPE_TEXT_VARIATION_PHONETIC:
986                 mOptLearning = false;
987                 mOptPrediction = false;
988                 break;
989             default:
990                 break;
991             }
992         }
993 
994         /* doesn't learn any word if it is not prediction mode */
995         if (!mOptPrediction) {
996             mOptLearning = false;
997         }
998 
999         /* set engine's mode */
1000         if (mOptSpellCorrection) {
1001             mConverterEN.setDictionary(OpenWnnEngineEN.DICT_FOR_CORRECT_MISTYPE);
1002         } else {
1003             mConverterEN.setDictionary(OpenWnnEngineEN.DICT_DEFAULT);
1004         }
1005         checkTutorial(info.privateImeOptions);
1006     }
1007 
1008     /**
1009      * Check and start the tutorial if it is the tutorial mode.
1010      *
1011      * @param privateImeOptions IME's options
1012      */
checkTutorial(String privateImeOptions)1013     private void checkTutorial(String privateImeOptions) {
1014         if (privateImeOptions == null) return;
1015         if (privateImeOptions.equals("com.android.setupwizard:ShowTutorial")) {
1016             if ((mTutorial == null) && mEnableTutorial) startTutorial();
1017         } else if (privateImeOptions.equals("com.android.setupwizard:HideTutorial")) {
1018             if (mTutorial != null) {
1019                 if (mTutorial.close()) {
1020                     mTutorial = null;
1021                 }
1022             }
1023         }
1024     }
1025 
1026     /**
1027      * Start the tutorial
1028      */
startTutorial()1029     private void startTutorial() {
1030         DefaultSoftKeyboardEN inputManager = ((DefaultSoftKeyboardEN) mInputViewManager);
1031         View v = inputManager.getKeyboardView();
1032         v.setOnTouchListener(new View.OnTouchListener() {
1033 				public boolean onTouch(View v, MotionEvent event) {
1034 					return true;
1035 				}});
1036         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500);
1037     }
1038 
1039     /**
1040      * Close the tutorial
1041      */
tutorialDone()1042     public void tutorialDone() {
1043         mTutorial = null;
1044     }
1045 
1046     /** @see OpenWnn#close */
close()1047     @Override protected void close() {
1048         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLOSE), 0);
1049     }
1050 }
1051