/ime/latinime/src/com/googlecode/eyesfree/inputmethod/PersistentInputMethodService.java
Java | 230 lines | 162 code | 32 blank | 36 comment | 29 complexity | fe8e9c81bcbe0df8d5ad94fc2bff2831 MD5 | raw file
1/* 2 * Copyright (C) 2011 Google Inc. 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 com.googlecode.eyesfree.inputmethod; 18 19import android.content.res.Configuration; 20import android.os.Handler; 21import android.os.Message; 22import android.util.Log; 23import android.view.KeyEvent; 24import android.view.ViewConfiguration; 25import android.view.WindowManager; 26import android.view.inputmethod.EditorInfo; 27import android.view.inputmethod.InputConnection; 28 29import com.google.android.marvin.aime.AccessibleInputMethodService; 30 31/** 32 * This class extends {@link AccessibleInputMethodService} by overriding methods 33 * related to hiding the input window. It allows the input method to be forced 34 * open by long-pressing the MENU key. 35 * 36 * @author alanv@google.com (Alan Viverette) 37 */ 38public class PersistentInputMethodService extends LinearNavigationInputMethodService { 39 private static final String TAG = "PersistentInputMethodService"; 40 private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); 41 private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 42 43 /** Constant used for LongPressHandler. */ 44 private static final int LONG_PRESS = 1; 45 46 private LongPressHandler mLongPressHandler; 47 48 /** 49 * Avoids handling repeated key presses. This is set after the first down 50 * event in a series of down events, then cleared on an up event. 51 */ 52 private KeyEvent mDownEvent; 53 54 private boolean mInLongPress; 55 56 private class LongPressHandler extends Handler { 57 LongPressHandler() { 58 super(); 59 } 60 61 @Override 62 public void handleMessage(Message msg) { 63 switch (msg.what) { 64 case LONG_PRESS: 65 mInLongPress = true; 66 onKeyLongPress(msg.arg1, (KeyEvent) msg.obj); 67 break; 68 } 69 } 70 } 71 72 @Override 73 public void onCreate() { 74 super.onCreate(); 75 76 mLongPressHandler = new LongPressHandler(); 77 } 78 79 @Override 80 public void onConfigurationChanged(Configuration newConfig) { 81 super.onConfigurationChanged(newConfig); 82 83 if (!isAccessibilityEnabled()) { 84 return; 85 } 86 87 // Ensure that we force the view open when accessibility is enabled, but 88 // only if we've already been attached to a window. 89 if (getWindow().getWindow().getAttributes().token != null) { 90 try { 91 showWindow(true); 92 } catch (RuntimeException e) { 93 e.printStackTrace(); 94 } 95 } 96 } 97 98 @Override 99 protected void onAccessibilityChanged(boolean accessibilityEnabled) { 100 if (!accessibilityEnabled) { 101 // This is the only correct way to hide the window. Don't use 102 // hideWindow() or requestHideSelf() because they'll mess up the 103 // internal state. 104 onCreateInputMethodInterface().hideSoftInput(0, null); 105 } 106 } 107 108 @Override 109 public boolean onKeyDown(int keyCode, KeyEvent event) { 110 if (!isAccessibilityEnabled()) { 111 return super.onKeyDown(keyCode, event); 112 } 113 114 switch (keyCode) { 115 case KeyEvent.KEYCODE_BACK: 116 return false; 117 case KeyEvent.KEYCODE_VOLUME_UP: 118 case KeyEvent.KEYCODE_VOLUME_DOWN: { 119 event.startTracking(); 120 if (mDownEvent == null) { 121 mDownEvent = event; 122 mInLongPress = false; 123 mLongPressHandler.removeMessages(LONG_PRESS); 124 mLongPressHandler.sendMessageDelayed( 125 mLongPressHandler.obtainMessage(LONG_PRESS, keyCode, 0, event), 126 TAP_TIMEOUT + LONGPRESS_TIMEOUT); 127 } 128 return true; 129 } 130 } 131 132 return super.onKeyDown(keyCode, event); 133 } 134 135 @Override 136 public boolean onKeyUp(int keyCode, KeyEvent event) { 137 if (!isAccessibilityEnabled()) { 138 return super.onKeyUp(keyCode, event); 139 } 140 141 final KeyEvent downEvent = mDownEvent; 142 mDownEvent = null; 143 144 // Give the parent class a chance to consume the cached down 145 // event, then send it through the input connection. 146 if (downEvent != null && !mInLongPress) { 147 final InputConnection input = getCurrentInputConnection(); 148 if (!super.onKeyDown(downEvent.getKeyCode(), downEvent) && input != null) { 149 input.sendKeyEvent(downEvent); 150 } 151 } 152 153 switch (keyCode) { 154 case KeyEvent.KEYCODE_BACK: 155 return false; 156 case KeyEvent.KEYCODE_VOLUME_UP: 157 case KeyEvent.KEYCODE_VOLUME_DOWN: { 158 mLongPressHandler.removeMessages(LONG_PRESS); 159 if (mInLongPress) { 160 mInLongPress = false; 161 return true; 162 } else { 163 return super.onKeyUp(keyCode, event); 164 } 165 } 166 } 167 168 return super.onKeyUp(keyCode, event); 169 } 170 171 @Override 172 public void onStartInput(EditorInfo attribute, boolean restarting) { 173 super.onStartInput(attribute, restarting); 174 175 if (!isAccessibilityEnabled()) { 176 return; 177 } 178 179 // Restart input view when changing input. 180 onStartInputView(attribute, restarting); 181 } 182 183 @Override 184 public void hideWindow() { 185 if (!isAccessibilityEnabled()) { 186 super.hideWindow(); 187 } 188 } 189 190 @Override 191 public void showWindow(boolean showInput) { 192 if (!isAccessibilityEnabled()) { 193 super.showWindow(showInput); 194 } else { 195 try { 196 super.showWindow(true); 197 } catch (WindowManager.BadTokenException e) { 198 Log.e(TAG, "Failed to show window", e); 199 } 200 } 201 } 202 203 @Override 204 public boolean onShowInputRequested(int flags, boolean configChange) { 205 if (!isAccessibilityEnabled()) { 206 return super.onShowInputRequested(flags, configChange); 207 } else { 208 return true; 209 } 210 } 211 212 @Override 213 public boolean onEvaluateInputViewShown() { 214 if (!isAccessibilityEnabled()) { 215 return super.onEvaluateInputViewShown(); 216 } else { 217 return true; 218 } 219 } 220 221 @Override 222 public boolean onEvaluateFullscreenMode() { 223 if (!isAccessibilityEnabled()) { 224 return super.onEvaluateFullscreenMode(); 225 } else { 226 // This input method should never show an extract view. 227 return false; 228 } 229 } 230}