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 */ 86 public OpenWnn() { 87 super(); 88 } 89 90 /*********************************************************************** 91 * InputMethodService 92 **********************************************************************/ 93 /** @see android.inputmethodservice.InputMethodService#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 */ 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 */ 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 */ 154 @Override public void onDestroy() { 155 super.onDestroy(); 156 mCurrentIme = null; 157 close(); 158 } 159 160 /** @see android.inputmethodservice.InputMethodService#onKeyDown */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 269 @Override public void hideWindow() { 270 super.hideWindow(); 271 mDirectInputMode = true; 272 hideStatusIcon(); 273 } 274 /** @see android.inputmethodservice.InputMethodService#onComputeInsets */ 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 */ 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 */ 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 */ 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 */ 337 public static boolean isXLarge() { 338 return mIsXLarge; 339 } 340 341 /** 342 * Update the x large mode. 343 */ 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 */ 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 */ 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 */ 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