diff options
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility')
-rw-r--r-- | java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java | 47 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java | 27 |
2 files changed, 60 insertions, 14 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index 86a56308a..1619451f0 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -20,12 +20,18 @@ import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.Paint; +import android.inputmethodservice.InputMethodService; +import android.media.AudioManager; import android.util.Log; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; +import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.AccessibilityEventCompatUtils; +import com.android.inputmethod.compat.AudioManagerCompatWrapper; +import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.MotionEventCompatUtils; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; @@ -39,17 +45,19 @@ public class AccessibleKeyboardViewProxy { // Delay in milliseconds between key press DOWN and UP events private static final long DELAY_KEY_PRESS = 10; - private int mScaledEdgeSlop; + private InputMethodService mInputMethod; + private FlickGestureDetector mGestureDetector; private LatinKeyboardBaseView mView; private AccessibleKeyboardActionListener mListener; - private FlickGestureDetector mGestureDetector; + private AudioManagerCompatWrapper mAudioManager; + private int mScaledEdgeSlop; private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY; private int mLastX = -1; private int mLastY = -1; - public static void init(Context context, SharedPreferences prefs) { - sInstance.initInternal(context, prefs); + public static void init(InputMethodService inputMethod, SharedPreferences prefs) { + sInstance.initInternal(inputMethod, prefs); sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance(); } @@ -65,15 +73,36 @@ public class AccessibleKeyboardViewProxy { // Not publicly instantiable. } - private void initInternal(Context context, SharedPreferences prefs) { + private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) { final Paint paint = new Paint(); paint.setTextAlign(Paint.Align.LEFT); paint.setTextSize(14.0f); paint.setAntiAlias(true); paint.setColor(Color.YELLOW); - mGestureDetector = new KeyboardFlickGestureDetector(context); - mScaledEdgeSlop = ViewConfiguration.get(context).getScaledEdgeSlop(); + mInputMethod = inputMethod; + mGestureDetector = new KeyboardFlickGestureDetector(inputMethod); + mScaledEdgeSlop = ViewConfiguration.get(inputMethod).getScaledEdgeSlop(); + + final AudioManager audioManager = (AudioManager) inputMethod + .getSystemService(Context.AUDIO_SERVICE); + mAudioManager = new AudioManagerCompatWrapper(audioManager); + } + + /** + * @return {@code true} if the device should not speak text (eg. non-control) characters + */ + private boolean shouldObscureInput() { + // Always speak if the user is listening through headphones. + if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) + return false; + + final EditorInfo info = mInputMethod.getCurrentInputEditorInfo(); + if (info == null) + return false; + + // Don't speak if the IME is connected to a password field. + return InputTypeCompatUtils.isPasswordInputType(info.inputType); } public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event, @@ -90,8 +119,10 @@ public class AccessibleKeyboardViewProxy { if (key == null) break; + final boolean shouldObscure = shouldObscureInput(); final CharSequence description = KeyCodeDescriptionMapper.getInstance() - .getDescriptionForKey(mView.getContext(), mView.getKeyboard(), key); + .getDescriptionForKey(mView.getContext(), mView.getKeyboard(), key, + shouldObscure); if (description == null) return false; diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index ec4287dda..7302830d4 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -28,6 +28,9 @@ import com.android.inputmethod.latin.R; import java.util.HashMap; public class KeyCodeDescriptionMapper { + // The resource ID of the string spoken for obscured keys + private static final int OBSCURED_KEY_RES_ID = R.string.spoken_description_dot; + private static KeyCodeDescriptionMapper sInstance = new KeyCodeDescriptionMapper(); // Map of key labels to spoken description resource IDs @@ -118,10 +121,12 @@ public class KeyCodeDescriptionMapper { * @param context The package's context. * @param keyboard The keyboard on which the key resides. * @param key The key from which to obtain a description. + * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured. * @return a character sequence describing the action performed by pressing * the key */ - public CharSequence getDescriptionForKey(Context context, Keyboard keyboard, Key key) { + public CharSequence getDescriptionForKey(Context context, Keyboard keyboard, Key key, + boolean shouldObscure) { if (key.mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { final CharSequence description = getDescriptionForSwitchAlphaSymbol(context, keyboard); if (description != null) @@ -136,12 +141,12 @@ public class KeyCodeDescriptionMapper { } else if (label.length() == 1 || (keyboard.isManualTemporaryUpperCase() && !TextUtils .isEmpty(key.mHintLabel))) { - return getDescriptionForKeyCode(context, keyboard, key); + return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); } else { return label; } } else if (key.mCode != Keyboard.CODE_DUMMY) { - return getDescriptionForKeyCode(context, keyboard, key); + return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); } return null; @@ -206,19 +211,29 @@ public class KeyCodeDescriptionMapper { * @param context The package's context. * @param keyboard The keyboard on which the key resides. * @param key The key from which to obtain a description. + * @param shouldObscure {@true} if text (e.g. non-control) characters should be obscured. * @return a character sequence describing the action performed by pressing * the key */ - private CharSequence getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key) { + private CharSequence getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key, + boolean shouldObscure) { final int code = getCorrectKeyCode(keyboard, key); if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) { return context.getString(mShiftLockedKeyCodeMap.get(code)); } else if (keyboard.isShiftedOrShiftLocked() && mShiftedKeyCodeMap.containsKey(code)) { return context.getString(mShiftedKeyCodeMap.get(code)); - } else if (mKeyCodeMap.containsKey(code)) { + } + + // If the key description should be obscured, now is the time to do it. + final boolean isDefinedNonCtrl = Character.isDefined(code) && !Character.isISOControl(code); + if (shouldObscure && isDefinedNonCtrl) { + return context.getString(OBSCURED_KEY_RES_ID); + } + + if (mKeyCodeMap.containsKey(code)) { return context.getString(mKeyCodeMap.get(code)); - } else if (Character.isDefined(code) && !Character.isISOControl(code)) { + } else if (isDefinedNonCtrl) { return Character.toString((char) code); } else { return context.getString(R.string.spoken_description_unknown, code); |