1 /*
2  * Copyright (C) 2008-2012  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.JAJP.*;
20 import android.inputmethodservice.InputMethodService;
21 import android.view.WindowManager;
22 import android.content.Context;
23 import android.view.View;
24 import android.view.KeyEvent;
25 import android.view.MotionEvent;
26 import android.content.SharedPreferences;
27 import android.preference.PreferenceManager;
28 
29 import android.util.Log;
30 import android.os.*;
31 import android.view.inputmethod.*;
32 import android.content.res.Configuration;
33 import android.graphics.*;
34 import android.graphics.drawable.*;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 
39 import jp.co.omronsoft.openwnn.KeyAction;
40 
41 /**
42  * The OpenWnn IME's base class.
43  *
44  * @author Copyright (C) 2009-2011 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
45  */
46 public class OpenWnn extends InputMethodService {
47 
48     /** Candidate view */
49     protected CandidatesViewManager  mCandidatesViewManager = null;
50     /** Input view (software keyboard) */
51     protected InputViewManager  mInputViewManager = null;
52     /** Conversion engine */
53     protected WnnEngine  mConverter = null;
54     /** Pre-converter (for Romaji-to-Kana input, Hangul input, etc.) */
55     protected LetterConverter  mPreConverter = null;
56     /** The inputing/editing string */
57     protected ComposingText  mComposingText = null;
58     /** The input connection */
59     protected InputConnection mInputConnection = null;
60     /** Auto hide candidate view */
61     protected boolean mAutoHideMode = true;
62     /** Direct input mode */
63     protected boolean mDirectInputMode = true;
64 
65     /** Flag for checking if the previous down key event is consumed by OpenWnn  */
66     private boolean mConsumeDownEvent;
67 
68     /** for isXLarge */
69     private static boolean mIsXLarge = false;
70 
71     /** TextCandidatesViewManager */
72     protected TextCandidatesViewManager mTextCandidatesViewManager = null;
73 
74     /** TextCandidates1LineViewManager */
75     protected TextCandidates1LineViewManager mTextCandidates1LineViewManager = null;
76 
77     /** The instance of current IME */
78     private static OpenWnn mCurrentIme;
79 
80     /** KeyAction list */
81     private List<KeyAction> KeyActionList = new ArrayList<KeyAction>();
82 
83     /**
84      * Constructor
85      */
OpenWnn()86     public OpenWnn() {
87         super();
88     }
89 
90     /***********************************************************************
91      * InputMethodService
92      **********************************************************************/
93     /** @see android.inputmethodservice.InputMethodService#onCreate */
onCreate()94     @Override public void onCreate() {
95         updateXLargeMode();
96         super.onCreate();
97 
98         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
99 
100         mCurrentIme = this;
101 
102 
103         mTextCandidatesViewManager = new TextCandidatesViewManager(-1);
104         if (isXLarge()) {
105             mTextCandidates1LineViewManager =
106                 new TextCandidates1LineViewManager(OpenWnnEngineJAJP.LIMIT_OF_CANDIDATES_1LINE);
107             mCandidatesViewManager = mTextCandidates1LineViewManager;
108         } else {
109             mCandidatesViewManager = mTextCandidatesViewManager;
110         }
111 
112         if (mConverter != null) { mConverter.init(); }
113         if (mComposingText != null) { mComposingText.clear(); }
114     }
115 
116     /** @see android.inputmethodservice.InputMethodService#onCreateCandidatesView */
onCreateCandidatesView()117     @Override public View onCreateCandidatesView() {
118         if (mCandidatesViewManager != null) {
119             WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
120             if (isXLarge()) {
121                 mCandidatesViewManager = mTextCandidates1LineViewManager;
122                 mTextCandidatesViewManager.initView(this,
123                                                         wm.getDefaultDisplay().getWidth(),
124                                                         wm.getDefaultDisplay().getHeight());
125             } else {
126                 mCandidatesViewManager = mTextCandidatesViewManager;
127             }
128             View view = mCandidatesViewManager.initView(this,
129                                                         wm.getDefaultDisplay().getWidth(),
130                                                         wm.getDefaultDisplay().getHeight());
131             mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
132             return view;
133         } else {
134             return super.onCreateCandidatesView();
135         }
136     }
137 
138     /** @see android.inputmethodservice.InputMethodService#onCreateInputView */
onCreateInputView()139     @Override public View onCreateInputView() {
140         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
141 
142 
143         if (mInputViewManager != null) {
144             WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
145             return mInputViewManager.initView(this,
146                                               wm.getDefaultDisplay().getWidth(),
147                                               wm.getDefaultDisplay().getHeight());
148         } else {
149             return super.onCreateInputView();
150         }
151     }
152 
153     /** @see android.inputmethodservice.InputMethodService#onDestroy */
onDestroy()154     @Override public void onDestroy() {
155         super.onDestroy();
156         mCurrentIme = null;
157         close();
158     }
159 
160     /** @see android.inputmethodservice.InputMethodService#onKeyDown */
onKeyDown(int keyCode, KeyEvent event)161     @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
162         mConsumeDownEvent = onEvent(new OpenWnnEvent(event));
163 
164         KeyAction Keycodeinfo = new KeyAction();
165         Keycodeinfo.mConsumeDownEvent = mConsumeDownEvent;
166         Keycodeinfo.mKeyCode = keyCode;
167 
168         int cnt = KeyActionList.size();
169         if (cnt != 0) {
170             for (int i = 0; i < cnt; i++) {
171                 if (KeyActionList.get(i).mKeyCode == keyCode) {
172                     KeyActionList.remove(i);
173                     break;
174                 }
175             }
176         }
177         KeyActionList.add(Keycodeinfo);
178         if (!mConsumeDownEvent) {
179             return super.onKeyDown(keyCode, event);
180         }
181         return mConsumeDownEvent;
182     }
183 
184     /** @see android.inputmethodservice.InputMethodService#onKeyUp */
onKeyUp(int keyCode, KeyEvent event)185     @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
186         boolean ret = mConsumeDownEvent;
187         int cnt = KeyActionList.size();
188         for (int i = 0; i < cnt; i++) {
189             KeyAction Keycodeinfo = KeyActionList.get(i);
190             if (Keycodeinfo.mKeyCode == keyCode) {
191                 ret = Keycodeinfo.mConsumeDownEvent;
192                 KeyActionList.remove(i);
193                 break;
194             }
195         }
196         if (!ret) {
197             ret = super.onKeyUp(keyCode, event);
198         }else{
199             ret = onEvent(new OpenWnnEvent(event));
200         }
201         return ret;
202     }
203 
204     /**
205      * Called when the key long press event occurred.
206      *
207      * @see android.inputmethodservice.InputMethodService#onKeyLongPress
208      */
onKeyLongPress(int keyCode, KeyEvent event)209     @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) {
210         if (mCurrentIme == null) {
211             Log.e("iWnn", "OpenWnn::onKeyLongPress()  Unprocessing onCreate() ");
212             return super.onKeyLongPress(keyCode, event);
213         }
214 
215         OpenWnnEvent wnnEvent = new OpenWnnEvent(event);
216         wnnEvent.code = OpenWnnEvent.KEYLONGPRESS;
217         return onEvent(wnnEvent);
218     }
219 
220     /** @see android.inputmethodservice.InputMethodService#onStartInput */
onStartInput(EditorInfo attribute, boolean restarting)221     @Override public void onStartInput(EditorInfo attribute, boolean restarting) {
222         super.onStartInput(attribute, restarting);
223         mInputConnection = getCurrentInputConnection();
224         if (!restarting && mComposingText != null) {
225             mComposingText.clear();
226         }
227     }
228 
229     /** @see android.inputmethodservice.InputMethodService#onStartInputView */
onStartInputView(EditorInfo attribute, boolean restarting)230     @Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
231         super.onStartInputView(attribute, restarting);
232         mInputConnection = getCurrentInputConnection();
233 
234         setCandidatesViewShown(false);
235         if (mInputConnection != null) {
236             mDirectInputMode = false;
237             if (mConverter != null) { mConverter.init(); }
238         } else {
239             mDirectInputMode = true;
240         }
241         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
242         if (mCandidatesViewManager != null) { mCandidatesViewManager.setPreferences(pref);  }
243         if (mInputViewManager != null) { mInputViewManager.setPreferences(pref, attribute);  }
244         if (mPreConverter != null) { mPreConverter.setPreferences(pref);  }
245         if (mConverter != null) { mConverter.setPreferences(pref);  }
246     }
247 
248     /** @see android.inputmethodservice.InputMethodService#requestHideSelf */
requestHideSelf(int flag)249     @Override public void requestHideSelf(int flag) {
250         super.requestHideSelf(flag);
251         if (mInputViewManager == null) {
252             hideWindow();
253         }
254     }
255 
256     /** @see android.inputmethodservice.InputMethodService#setCandidatesViewShown */
setCandidatesViewShown(boolean shown)257     @Override public void setCandidatesViewShown(boolean shown) {
258         super.setCandidatesViewShown(shown);
259         if (shown) {
260             showWindow(true);
261         } else {
262             if (mAutoHideMode && mInputViewManager == null) {
263                 hideWindow();
264             }
265         }
266     }
267 
268     /** @see android.inputmethodservice.InputMethodService#hideWindow */
hideWindow()269     @Override public void hideWindow() {
270         super.hideWindow();
271         mDirectInputMode = true;
272         hideStatusIcon();
273     }
274     /** @see android.inputmethodservice.InputMethodService#onComputeInsets */
onComputeInsets(InputMethodService.Insets outInsets)275     @Override public void onComputeInsets(InputMethodService.Insets outInsets) {
276         super.onComputeInsets(outInsets);
277         outInsets.contentTopInsets = outInsets.visibleTopInsets;
278     }
279 
280 
281     /**********************************************************************
282      * OpenWnn
283      **********************************************************************/
284     /**
285      * Process an event.
286      *
287      * @param  ev  An event
288      * @return  {@code true} if the event is processed in this method; {@code false} if not.
289      */
onEvent(OpenWnnEvent ev)290     public boolean onEvent(OpenWnnEvent ev) {
291         return false;
292     }
293 
294     /**
295      * Search a character for toggle input.
296      *
297      * @param prevChar     The character input previous
298      * @param toggleTable  Toggle table
299      * @param reverse      {@code false} if toggle direction is forward, {@code true} if toggle direction is backward
300      * @return          A character ({@code null} if no character is found)
301      */
searchToggleCharacter(String prevChar, String[] toggleTable, boolean reverse)302     protected String searchToggleCharacter(String prevChar, String[] toggleTable, boolean reverse) {
303         for (int i = 0; i < toggleTable.length; i++) {
304             if (prevChar.equals(toggleTable[i])) {
305                 if (reverse) {
306                     i--;
307                     if (i < 0) {
308                         return toggleTable[toggleTable.length - 1];
309                     } else {
310                         return toggleTable[i];
311                     }
312                 } else {
313                     i++;
314                     if (i == toggleTable.length) {
315                         return toggleTable[0];
316                     } else {
317                         return toggleTable[i];
318                     }
319                 }
320             }
321         }
322         return null;
323     }
324 
325     /**
326      * Processing of resource open when IME ends.
327      */
close()328     protected void close() {
329         if (mConverter != null) { mConverter.close(); }
330     }
331 
332     /**
333      * Whether the x large mode.
334      *
335      * @return      {@code true} if x large; {@code false} if not x large.
336      */
isXLarge()337     public static boolean isXLarge() {
338         return mIsXLarge;
339     }
340 
341     /**
342      * Update the x large mode.
343      */
updateXLargeMode()344     public void updateXLargeMode() {
345         mIsXLarge = ((getResources().getConfiguration().screenLayout &
346                       Configuration.SCREENLAYOUT_SIZE_MASK)
347                       == Configuration.SCREENLAYOUT_SIZE_XLARGE);
348     }
349 
350     /**
351      * Get the instance of current IME.
352      *
353      * @return the instance of current IME, See {@link jp.co.omronsoft.openwnn.OpenWnn}
354      */
getCurrentIme()355     public static OpenWnn getCurrentIme() {
356         return mCurrentIme;
357     }
358 
359     /**
360      * Check through key code in IME.
361      *
362      * @param keyCode  check key code.
363      * @return {@code true} if through key code; {@code false} otherwise.
364      */
isThroughKeyCode(int keyCode)365     protected boolean isThroughKeyCode(int keyCode) {
366         boolean result;
367         switch (keyCode) {
368         case KeyEvent.KEYCODE_CALL:
369         case KeyEvent.KEYCODE_VOLUME_DOWN:
370         case KeyEvent.KEYCODE_VOLUME_UP:
371         case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
372         case KeyEvent.KEYCODE_MEDIA_NEXT:
373         case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
374         case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
375         case KeyEvent.KEYCODE_MEDIA_REWIND:
376         case KeyEvent.KEYCODE_MEDIA_STOP:
377         case KeyEvent.KEYCODE_MUTE:
378         case KeyEvent.KEYCODE_HEADSETHOOK:
379         case KeyEvent.KEYCODE_VOLUME_MUTE:
380         case KeyEvent.KEYCODE_MEDIA_CLOSE:
381         case KeyEvent.KEYCODE_MEDIA_EJECT:
382         case KeyEvent.KEYCODE_MEDIA_PAUSE:
383         case KeyEvent.KEYCODE_MEDIA_PLAY:
384         case KeyEvent.KEYCODE_MEDIA_RECORD:
385         case KeyEvent.KEYCODE_MANNER_MODE:
386             result = true;
387             break;
388 
389         default:
390             result = false;
391             break;
392 
393         }
394         return result;
395     }
396 
397     /**
398      * Check ten-key code.
399      *
400      * @param keyCode  check key code.
401      * @return {@code true} if ten-key code; {@code false} not ten-key code.
402      */
isTenKeyCode(int keyCode)403     protected boolean isTenKeyCode(int keyCode) {
404         boolean result = false;
405         switch (keyCode) {
406         case KeyEvent.KEYCODE_NUMPAD_0:
407         case KeyEvent.KEYCODE_NUMPAD_1:
408         case KeyEvent.KEYCODE_NUMPAD_2:
409         case KeyEvent.KEYCODE_NUMPAD_3:
410         case KeyEvent.KEYCODE_NUMPAD_4:
411         case KeyEvent.KEYCODE_NUMPAD_5:
412         case KeyEvent.KEYCODE_NUMPAD_6:
413         case KeyEvent.KEYCODE_NUMPAD_7:
414         case KeyEvent.KEYCODE_NUMPAD_8:
415         case KeyEvent.KEYCODE_NUMPAD_9:
416         case KeyEvent.KEYCODE_NUMPAD_DOT:
417             result = true;
418             break;
419 
420         default:
421             break;
422 
423         }
424         return result;
425     }
426 }
427