Skip to content
Snippets Groups Projects
Commit e4861759 authored by Ken Wakasa's avatar Ken Wakasa Committed by Android (Google) Code Review
Browse files

Merge "Fixed speaking keys when editing password fields"

parents 5cb10f78 58e3f106
No related branches found
No related tags found
No related merge requests found
...@@ -20,12 +20,18 @@ import android.content.Context; ...@@ -20,12 +20,18 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.compat.AccessibilityEventCompatUtils; 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.compat.MotionEventCompatUtils;
import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.KeyDetector;
...@@ -39,17 +45,19 @@ public class AccessibleKeyboardViewProxy { ...@@ -39,17 +45,19 @@ public class AccessibleKeyboardViewProxy {
// Delay in milliseconds between key press DOWN and UP events // Delay in milliseconds between key press DOWN and UP events
private static final long DELAY_KEY_PRESS = 10; private static final long DELAY_KEY_PRESS = 10;
private int mScaledEdgeSlop; private InputMethodService mInputMethod;
private FlickGestureDetector mGestureDetector;
private LatinKeyboardBaseView mView; private LatinKeyboardBaseView mView;
private AccessibleKeyboardActionListener mListener; private AccessibleKeyboardActionListener mListener;
private FlickGestureDetector mGestureDetector; private AudioManagerCompatWrapper mAudioManager;
private int mScaledEdgeSlop;
private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY; private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY;
private int mLastX = -1; private int mLastX = -1;
private int mLastY = -1; private int mLastY = -1;
public static void init(Context context, SharedPreferences prefs) { public static void init(InputMethodService inputMethod, SharedPreferences prefs) {
sInstance.initInternal(context, prefs); sInstance.initInternal(inputMethod, prefs);
sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance(); sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance();
} }
...@@ -65,15 +73,36 @@ public class AccessibleKeyboardViewProxy { ...@@ -65,15 +73,36 @@ public class AccessibleKeyboardViewProxy {
// Not publicly instantiable. // Not publicly instantiable.
} }
private void initInternal(Context context, SharedPreferences prefs) { private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) {
final Paint paint = new Paint(); final Paint paint = new Paint();
paint.setTextAlign(Paint.Align.LEFT); paint.setTextAlign(Paint.Align.LEFT);
paint.setTextSize(14.0f); paint.setTextSize(14.0f);
paint.setAntiAlias(true); paint.setAntiAlias(true);
paint.setColor(Color.YELLOW); paint.setColor(Color.YELLOW);
mGestureDetector = new KeyboardFlickGestureDetector(context); mInputMethod = inputMethod;
mScaledEdgeSlop = ViewConfiguration.get(context).getScaledEdgeSlop(); 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, public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event,
...@@ -90,8 +119,10 @@ public class AccessibleKeyboardViewProxy { ...@@ -90,8 +119,10 @@ public class AccessibleKeyboardViewProxy {
if (key == null) if (key == null)
break; break;
final boolean shouldObscure = shouldObscureInput();
final CharSequence description = KeyCodeDescriptionMapper.getInstance() final CharSequence description = KeyCodeDescriptionMapper.getInstance()
.getDescriptionForKey(mView.getContext(), mView.getKeyboard(), key); .getDescriptionForKey(mView.getContext(), mView.getKeyboard(), key,
shouldObscure);
if (description == null) if (description == null)
return false; return false;
......
...@@ -28,6 +28,9 @@ import com.android.inputmethod.latin.R; ...@@ -28,6 +28,9 @@ import com.android.inputmethod.latin.R;
import java.util.HashMap; import java.util.HashMap;
public class KeyCodeDescriptionMapper { 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(); private static KeyCodeDescriptionMapper sInstance = new KeyCodeDescriptionMapper();
// Map of key labels to spoken description resource IDs // Map of key labels to spoken description resource IDs
...@@ -118,10 +121,12 @@ public class KeyCodeDescriptionMapper { ...@@ -118,10 +121,12 @@ public class KeyCodeDescriptionMapper {
* @param context The package's context. * @param context The package's context.
* @param keyboard The keyboard on which the key resides. * @param keyboard The keyboard on which the key resides.
* @param key The key from which to obtain a description. * @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 * @return a character sequence describing the action performed by pressing
* the key * 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) { if (key.mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
final CharSequence description = getDescriptionForSwitchAlphaSymbol(context, keyboard); final CharSequence description = getDescriptionForSwitchAlphaSymbol(context, keyboard);
if (description != null) if (description != null)
...@@ -136,12 +141,12 @@ public class KeyCodeDescriptionMapper { ...@@ -136,12 +141,12 @@ public class KeyCodeDescriptionMapper {
} else if (label.length() == 1 } else if (label.length() == 1
|| (keyboard.isManualTemporaryUpperCase() && !TextUtils || (keyboard.isManualTemporaryUpperCase() && !TextUtils
.isEmpty(key.mHintLabel))) { .isEmpty(key.mHintLabel))) {
return getDescriptionForKeyCode(context, keyboard, key); return getDescriptionForKeyCode(context, keyboard, key, shouldObscure);
} else { } else {
return label; return label;
} }
} else if (key.mCode != Keyboard.CODE_DUMMY) { } else if (key.mCode != Keyboard.CODE_DUMMY) {
return getDescriptionForKeyCode(context, keyboard, key); return getDescriptionForKeyCode(context, keyboard, key, shouldObscure);
} }
return null; return null;
...@@ -206,19 +211,29 @@ public class KeyCodeDescriptionMapper { ...@@ -206,19 +211,29 @@ public class KeyCodeDescriptionMapper {
* @param context The package's context. * @param context The package's context.
* @param keyboard The keyboard on which the key resides. * @param keyboard The keyboard on which the key resides.
* @param key The key from which to obtain a description. * @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 * @return a character sequence describing the action performed by pressing
* the key * 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); final int code = getCorrectKeyCode(keyboard, key);
if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) { if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) {
return context.getString(mShiftLockedKeyCodeMap.get(code)); return context.getString(mShiftLockedKeyCodeMap.get(code));
} else if (keyboard.isShiftedOrShiftLocked() && mShiftedKeyCodeMap.containsKey(code)) { } else if (keyboard.isShiftedOrShiftLocked() && mShiftedKeyCodeMap.containsKey(code)) {
return context.getString(mShiftedKeyCodeMap.get(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)); return context.getString(mKeyCodeMap.get(code));
} else if (Character.isDefined(code) && !Character.isISOControl(code)) { } else if (isDefinedNonCtrl) {
return Character.toString((char) code); return Character.toString((char) code);
} else { } else {
return context.getString(R.string.spoken_description_unknown, code); return context.getString(R.string.spoken_description_unknown, code);
......
/*
* 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.compat;
import android.media.AudioManager;
import java.lang.reflect.Method;
public class AudioManagerCompatWrapper {
private static final Method METHOD_isWiredHeadsetOn = CompatUtils.getMethod(
AudioManager.class, "isWiredHeadsetOn");
private static final Method METHOD_isBluetoothA2dpOn = CompatUtils.getMethod(
AudioManager.class, "isBluetoothA2dpOn");
private final AudioManager mManager;
public AudioManagerCompatWrapper(AudioManager manager) {
mManager = manager;
}
/**
* Checks whether audio routing to the wired headset is on or off.
*
* @return true if audio is being routed to/from wired headset;
* false if otherwise
*/
public boolean isWiredHeadsetOn() {
return (Boolean) CompatUtils.invoke(mManager, false, METHOD_isWiredHeadsetOn);
}
/**
* Checks whether A2DP audio routing to the Bluetooth headset is on or off.
*
* @return true if A2DP audio is being routed to/from Bluetooth headset;
* false if otherwise
*/
public boolean isBluetoothA2dpOn() {
return (Boolean) CompatUtils.invoke(mManager, false, METHOD_isBluetoothA2dpOn);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment