aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java172
1 files changed, 172 insertions, 0 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
new file mode 100644
index 000000000..89adc15f2
--- /dev/null
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.accessibility;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.inputmethodservice.InputMethodService;
+import android.media.AudioManager;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Vibrator;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+
+public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener {
+ private static final AccessibleInputMethodServiceProxy sInstance =
+ new AccessibleInputMethodServiceProxy();
+
+ /*
+ * Delay for the handler event that's fired when Accessibility is on and the
+ * user hovers outside of any valid keys. This is used to let the user know
+ * that if they lift their finger, nothing will be typed.
+ */
+ private static final long DELAY_NO_HOVER_SELECTION = 250;
+
+ /**
+ * Duration of the key click vibration in milliseconds.
+ */
+ private static final long VIBRATE_KEY_CLICK = 50;
+
+ private InputMethodService mInputMethod;
+ private Vibrator mVibrator;
+ private AudioManager mAudioManager;
+ private AccessibilityHandler mAccessibilityHandler;
+
+ private static class AccessibilityHandler
+ extends StaticInnerHandlerWrapper<AccessibleInputMethodServiceProxy> {
+ private static final int MSG_NO_HOVER_SELECTION = 0;
+
+ public AccessibilityHandler(AccessibleInputMethodServiceProxy outerInstance,
+ Looper looper) {
+ super(outerInstance, looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_NO_HOVER_SELECTION:
+ getOuterInstance().notifyNoHoverSelection();
+ break;
+ }
+ }
+
+ public void postNoHoverSelection() {
+ removeMessages(MSG_NO_HOVER_SELECTION);
+ sendEmptyMessageDelayed(MSG_NO_HOVER_SELECTION, DELAY_NO_HOVER_SELECTION);
+ }
+
+ public void cancelNoHoverSelection() {
+ removeMessages(MSG_NO_HOVER_SELECTION);
+ }
+ }
+
+ public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
+ sInstance.initInternal(inputMethod, prefs);
+ }
+
+ public static AccessibleInputMethodServiceProxy getInstance() {
+ return sInstance;
+ }
+
+ private AccessibleInputMethodServiceProxy() {
+ // Not publicly instantiable.
+ }
+
+ private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) {
+ mInputMethod = inputMethod;
+ mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE);
+ mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE);
+ mAccessibilityHandler = new AccessibilityHandler(this, inputMethod.getMainLooper());
+ }
+
+ /**
+ * If touch exploration is enabled, cancels the event sent by
+ * {@link AccessibleInputMethodServiceProxy#onHoverExit(int)} because the
+ * user is currently hovering above a key.
+ */
+ @Override
+ public void onHoverEnter(int primaryCode) {
+ mAccessibilityHandler.cancelNoHoverSelection();
+ }
+
+ /**
+ * If touch exploration is enabled, sends a delayed event to notify the user
+ * that they are not currently hovering above a key.
+ */
+ @Override
+ public void onHoverExit(int primaryCode) {
+ mAccessibilityHandler.postNoHoverSelection();
+ }
+
+ /**
+ * Handle flick gestures by mapping them to directional pad keys.
+ */
+ @Override
+ public void onFlickGesture(int direction) {
+ final int keyEventCode;
+
+ switch (direction) {
+ case FlickGestureDetector.FLICK_LEFT:
+ sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
+ break;
+ case FlickGestureDetector.FLICK_RIGHT:
+ sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
+ break;
+ }
+ }
+
+ /**
+ * Provide haptic feedback and send the specified keyCode to the input
+ * connection as a pair of down/up events.
+ *
+ * @param keyCode
+ */
+ private void sendDownUpKeyEvents(int keyCode) {
+ mVibrator.vibrate(VIBRATE_KEY_CLICK);
+ mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
+ mInputMethod.sendDownUpKeyEvents(keyCode);
+ }
+
+ /**
+ * When Accessibility is turned on, notifies the user that they are not
+ * currently hovering above a key. By default this will speak the currently
+ * entered text.
+ */
+ private void notifyNoHoverSelection() {
+ final ExtractedText extracted = mInputMethod.getCurrentInputConnection().getExtractedText(
+ new ExtractedTextRequest(), 0);
+
+ if (extracted == null)
+ return;
+
+ final CharSequence text;
+
+ if (TextUtils.isEmpty(extracted.text)) {
+ text = mInputMethod.getString(R.string.spoken_no_text_entered);
+ } else {
+ text = mInputMethod.getString(R.string.spoken_current_text_is, extracted.text);
+ }
+
+ AccessibilityUtils.getInstance().speak(text);
+ }
+}