aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/accessibility
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java134
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java64
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java163
-rw-r--r--java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java82
4 files changed, 255 insertions, 188 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index b9b6362fc..0576f666c 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -36,6 +36,7 @@ import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.CoordinateUtils;
/**
* Exposes a virtual view sub-tree for {@link KeyboardView} and generates
@@ -62,7 +63,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
private final Rect mTempBoundsInScreen = new Rect();
/** The parent view's cached on-screen location. */
- private final int[] mParentLocation = new int[2];
+ private final int[] mParentLocation = CoordinateUtils.newInstance();
/** The virtual view identifier for the focused node. */
private int mAccessibilityFocusedView = UNDEFINED;
@@ -70,12 +71,11 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
/** The current keyboard view. */
private KeyboardView mKeyboardView;
- public AccessibilityEntityProvider(KeyboardView keyboardView, InputMethodService inputMethod) {
+ public AccessibilityEntityProvider(final KeyboardView keyboardView,
+ final InputMethodService inputMethod) {
mInputMethodService = inputMethod;
-
mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance();
mAccessibilityUtils = AccessibilityUtils.getInstance();
-
setView(keyboardView);
}
@@ -84,21 +84,19 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
*
* @param keyboardView The keyboard view to represent.
*/
- public void setView(KeyboardView keyboardView) {
+ public void setView(final KeyboardView keyboardView) {
mKeyboardView = keyboardView;
updateParentLocation();
// Since this class is constructed lazily, we might not get a subsequent
// call to setKeyboard() and therefore need to call it now.
- setKeyboard(mKeyboardView.getKeyboard());
+ setKeyboard();
}
/**
* Sets the keyboard represented by this node provider.
- *
- * @param keyboard The keyboard to represent.
*/
- public void setKeyboard(Keyboard keyboard) {
+ public void setKeyboard() {
assignVirtualViewIds();
}
@@ -111,19 +109,16 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
* @return A populated {@link AccessibilityEvent} for the key.
* @see AccessibilityEvent
*/
- public AccessibilityEvent createAccessibilityEvent(Key key, int eventType) {
+ public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) {
final int virtualViewId = generateVirtualViewIdForKey(key);
final String keyDescription = getKeyDescription(key);
-
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
event.setPackageName(mKeyboardView.getContext().getPackageName());
event.setClassName(key.getClass().getName());
event.setContentDescription(keyDescription);
event.setEnabled(true);
-
final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event);
record.setSource(mKeyboardView, virtualViewId);
-
return event;
}
@@ -144,67 +139,65 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
* </p>
*
* @param virtualViewId A client defined virtual view id.
- * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual
- * descendant or the host View.
+ * @return A populated {@link AccessibilityNodeInfoCompat} for a virtual descendant or the host
+ * View.
* @see AccessibilityNodeInfoCompat
*/
@Override
- public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
- AccessibilityNodeInfoCompat info = null;
-
+ public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(final int virtualViewId) {
if (virtualViewId == UNDEFINED) {
return null;
- } else if (virtualViewId == View.NO_ID) {
+ }
+ if (virtualViewId == View.NO_ID) {
// We are requested to create an AccessibilityNodeInfo describing
// this View, i.e. the root of the virtual sub-tree.
- info = AccessibilityNodeInfoCompat.obtain(mKeyboardView);
- ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, info);
+ final AccessibilityNodeInfoCompat rootInfo =
+ AccessibilityNodeInfoCompat.obtain(mKeyboardView);
+ ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);
// Add the virtual children of the root View.
final Keyboard keyboard = mKeyboardView.getKeyboard();
final Key[] keys = keyboard.mKeys;
for (Key key : keys) {
final int childVirtualViewId = generateVirtualViewIdForKey(key);
- info.addChild(mKeyboardView, childVirtualViewId);
- }
- } else {
- // Find the view that corresponds to the given id.
- final Key key = mVirtualViewIdToKey.get(virtualViewId);
- if (key == null) {
- Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
- return null;
- }
-
- final String keyDescription = getKeyDescription(key);
- final Rect boundsInParent = key.mHitBox;
-
- // Calculate the key's in-screen bounds.
- mTempBoundsInScreen.set(boundsInParent);
- mTempBoundsInScreen.offset(mParentLocation[0], mParentLocation[1]);
-
- final Rect boundsInScreen = mTempBoundsInScreen;
-
- // Obtain and initialize an AccessibilityNodeInfo with
- // information about the virtual view.
- info = AccessibilityNodeInfoCompat.obtain();
- info.setPackageName(mKeyboardView.getContext().getPackageName());
- info.setClassName(key.getClass().getName());
- info.setContentDescription(keyDescription);
- info.setBoundsInParent(boundsInParent);
- info.setBoundsInScreen(boundsInScreen);
- info.setParent(mKeyboardView);
- info.setSource(mKeyboardView, virtualViewId);
- info.setBoundsInScreen(boundsInScreen);
- info.setEnabled(true);
- info.setVisibleToUser(true);
-
- if (mAccessibilityFocusedView == virtualViewId) {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
- } else {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
+ rootInfo.addChild(mKeyboardView, childVirtualViewId);
}
+ return rootInfo;
}
+ // Find the view that corresponds to the given id.
+ final Key key = mVirtualViewIdToKey.get(virtualViewId);
+ if (key == null) {
+ Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
+ return null;
+ }
+ final String keyDescription = getKeyDescription(key);
+ final Rect boundsInParent = key.mHitBox;
+
+ // Calculate the key's in-screen bounds.
+ mTempBoundsInScreen.set(boundsInParent);
+ mTempBoundsInScreen.offset(
+ CoordinateUtils.x(mParentLocation), CoordinateUtils.y(mParentLocation));
+ final Rect boundsInScreen = mTempBoundsInScreen;
+
+ // Obtain and initialize an AccessibilityNodeInfo with information about the virtual view.
+ final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ info.setPackageName(mKeyboardView.getContext().getPackageName());
+ info.setClassName(key.getClass().getName());
+ info.setContentDescription(keyDescription);
+ info.setBoundsInParent(boundsInParent);
+ info.setBoundsInScreen(boundsInScreen);
+ info.setParent(mKeyboardView);
+ info.setSource(mKeyboardView, virtualViewId);
+ info.setBoundsInScreen(boundsInScreen);
+ info.setEnabled(true);
+ info.setVisibleToUser(true);
+
+ if (mAccessibilityFocusedView == virtualViewId) {
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ } else {
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
+ }
return info;
}
@@ -214,7 +207,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
*
* @param key The key to press.
*/
- void simulateKeyPress(Key key) {
+ void simulateKeyPress(final Key key) {
final int x = key.mHitBox.centerX();
final int y = key.mHitBox.centerY();
final long downTime = SystemClock.uptimeMillis();
@@ -225,19 +218,17 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
mKeyboardView.onTouchEvent(downEvent);
mKeyboardView.onTouchEvent(upEvent);
-
downEvent.recycle();
upEvent.recycle();
}
@Override
- public boolean performAction(int virtualViewId, int action, Bundle arguments) {
+ public boolean performAction(final int virtualViewId, final int action,
+ final Bundle arguments) {
final Key key = mVirtualViewIdToKey.get(virtualViewId);
-
if (key == null) {
return false;
}
-
return performActionForKey(key, action, arguments);
}
@@ -247,10 +238,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
* @param key The on which to perform the action.
* @param action The action to perform.
* @param arguments The action's arguments.
- * @return The result of performing the action, or false if the action is
- * not supported.
+ * @return The result of performing the action, or false if the action is not supported.
*/
- boolean performActionForKey(Key key, int action, Bundle arguments) {
+ boolean performActionForKey(final Key key, final int action, final Bundle arguments) {
final int virtualViewId = generateVirtualViewIdForKey(key);
switch (action) {
@@ -270,9 +260,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
sendAccessibilityEventForKey(
key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
return true;
+ default:
+ return false;
}
-
- return false;
}
/**
@@ -281,7 +271,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
* @param key The key that's sending the event.
* @param eventType The type of event to send.
*/
- void sendAccessibilityEventForKey(Key key, int eventType) {
+ void sendAccessibilityEventForKey(final Key key, final int eventType) {
final AccessibilityEvent event = createAccessibilityEvent(key, eventType);
mAccessibilityUtils.requestSendAccessibilityEvent(event);
}
@@ -292,12 +282,11 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
* @param key The key to describe.
* @return The context-specific description of the key.
*/
- private String getKeyDescription(Key key) {
+ private String getKeyDescription(final Key key) {
final EditorInfo editorInfo = mInputMethodService.getCurrentInputEditorInfo();
final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo);
final String keyDescription = mKeyCodeDescriptionMapper.getDescriptionForKey(
mKeyboardView.getContext(), mKeyboardView.getKeyboard(), key, shouldObscure);
-
return keyDescription;
}
@@ -309,7 +298,6 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
if (keyboard == null) {
return;
}
-
mVirtualViewIdToKey.clear();
final Key[] keys = keyboard.mKeys;
@@ -333,7 +321,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
* @param key The key to identify.
* @return A virtual view identifier.
*/
- private static int generateVirtualViewIdForKey(Key key) {
+ private static int generateVirtualViewIdForKey(final Key key) {
// The key x- and y-coordinates are stable between layout changes.
// Generate an identifier by bit-shifting the x-coordinate to the
// left-half of the integer and OR'ing with the y-coordinate.
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index 1eee1df87..ee52de1d1 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -32,7 +32,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.EditorInfo;
-import com.android.inputmethod.compat.AudioManagerCompatWrapper;
import com.android.inputmethod.compat.SettingsSecureCompatUtils;
import com.android.inputmethod.latin.InputTypeUtils;
import com.android.inputmethod.latin.R;
@@ -40,14 +39,14 @@ import com.android.inputmethod.latin.R;
public final class AccessibilityUtils {
private static final String TAG = AccessibilityUtils.class.getSimpleName();
private static final String CLASS = AccessibilityUtils.class.getClass().getName();
- private static final String PACKAGE = AccessibilityUtils.class.getClass().getPackage()
- .getName();
+ private static final String PACKAGE =
+ AccessibilityUtils.class.getClass().getPackage().getName();
private static final AccessibilityUtils sInstance = new AccessibilityUtils();
private Context mContext;
private AccessibilityManager mAccessibilityManager;
- private AudioManagerCompatWrapper mAudioManager;
+ private AudioManager mAudioManager;
/*
* Setting this constant to {@code false} will disable all keyboard
@@ -56,9 +55,8 @@ public final class AccessibilityUtils {
*/
private static final boolean ENABLE_ACCESSIBILITY = true;
- public static void init(InputMethodService inputMethod) {
- if (!ENABLE_ACCESSIBILITY)
- return;
+ public static void init(final InputMethodService inputMethod) {
+ if (!ENABLE_ACCESSIBILITY) return;
// These only need to be initialized if the kill switch is off.
sInstance.initInternal(inputMethod);
@@ -74,27 +72,32 @@ public final class AccessibilityUtils {
// This class is not publicly instantiable.
}
- private void initInternal(Context context) {
+ private void initInternal(final Context context) {
mContext = context;
- mAccessibilityManager = (AccessibilityManager) context
- .getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mAccessibilityManager =
+ (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
- final AudioManager audioManager = (AudioManager) context
- .getSystemService(Context.AUDIO_SERVICE);
- mAudioManager = new AudioManagerCompatWrapper(audioManager);
+ /**
+ * Returns {@code true} if accessibility is enabled. Currently, this means
+ * that the kill switch is off and system accessibility is turned on.
+ *
+ * @return {@code true} if accessibility is enabled.
+ */
+ public boolean isAccessibilityEnabled() {
+ return ENABLE_ACCESSIBILITY && mAccessibilityManager.isEnabled();
}
/**
* Returns {@code true} if touch exploration is enabled. Currently, this
* means that the kill switch is off, the device supports touch exploration,
- * and a spoken feedback service is turned on.
+ * and system accessibility is turned on.
*
* @return {@code true} if touch exploration is enabled.
*/
public boolean isTouchExplorationEnabled() {
- return ENABLE_ACCESSIBILITY
- && mAccessibilityManager.isEnabled()
- && mAccessibilityManager.isTouchExplorationEnabled();
+ return isAccessibilityEnabled() && mAccessibilityManager.isTouchExplorationEnabled();
}
/**
@@ -105,9 +108,8 @@ public final class AccessibilityUtils {
* @param event The event to check.
* @return {@true} is the event is a touch exploration event
*/
- public boolean isTouchExplorationEvent(MotionEvent event) {
+ public boolean isTouchExplorationEvent(final MotionEvent event) {
final int action = event.getAction();
-
return action == MotionEvent.ACTION_HOVER_ENTER
|| action == MotionEvent.ACTION_HOVER_EXIT
|| action == MotionEvent.ACTION_HOVER_MOVE;
@@ -119,21 +121,21 @@ public final class AccessibilityUtils {
*
* @return {@code true} if the device should obscure password characters.
*/
- public boolean shouldObscureInput(EditorInfo editorInfo) {
- if (editorInfo == null)
- return false;
+ @SuppressWarnings("deprecation")
+ public boolean shouldObscureInput(final EditorInfo editorInfo) {
+ if (editorInfo == null) return false;
// The user can optionally force speaking passwords.
if (SettingsSecureCompatUtils.ACCESSIBILITY_SPEAK_PASSWORD != null) {
final boolean speakPassword = Settings.Secure.getInt(mContext.getContentResolver(),
SettingsSecureCompatUtils.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
- if (speakPassword)
- return false;
+ if (speakPassword) return false;
}
// Always speak if the user is listening through headphones.
- if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn())
+ if (mAudioManager.isWiredHeadsetOn() || mAudioManager.isBluetoothA2dpOn()) {
return false;
+ }
// Don't speak if the IME is connected to a password field.
return InputTypeUtils.isPasswordInputType(editorInfo.inputType);
@@ -146,7 +148,7 @@ public final class AccessibilityUtils {
* @param view The source view.
* @param text The text to speak.
*/
- public void announceForAccessibility(View view, CharSequence text) {
+ public void announceForAccessibility(final View view, final CharSequence text) {
if (!mAccessibilityManager.isEnabled()) {
Log.e(TAG, "Attempted to speak when accessibility was disabled!");
return;
@@ -163,8 +165,9 @@ public final class AccessibilityUtils {
event.setEnabled(true);
event.getText().add(text);
- // Platforms starting at SDK 16 should use announce events.
- if (Build.VERSION.SDK_INT >= 16) {
+ // Platforms starting at SDK version 16 (Build.VERSION_CODES.JELLY_BEAN) should use
+ // announce events.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
} else {
event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
@@ -187,7 +190,8 @@ public final class AccessibilityUtils {
* @param editorInfo The input connection's editor info attribute.
* @param restarting Whether the connection is being restarted.
*/
- public void onStartInputViewInternal(View view, EditorInfo editorInfo, boolean restarting) {
+ public void onStartInputViewInternal(final View view, final EditorInfo editorInfo,
+ final boolean restarting) {
if (shouldObscureInput(editorInfo)) {
final CharSequence text = mContext.getText(R.string.spoken_use_headphones);
announceForAccessibility(view, text);
@@ -200,7 +204,7 @@ public final class AccessibilityUtils {
*
* @param event The event to send.
*/
- public void requestSendAccessibilityEvent(AccessibilityEvent event) {
+ public void requestSendAccessibilityEvent(final AccessibilityEvent event) {
if (mAccessibilityManager.isEnabled()) {
mAccessibilityManager.sendAccessibilityEvent(event);
}
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
index fcfa6d4e4..e6b44120f 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -1,17 +1,17 @@
/*
* 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
+ * 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
+ * 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.
+ * 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;
@@ -22,8 +22,11 @@ import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -35,6 +38,21 @@ import com.android.inputmethod.latin.R;
public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy();
+ /** Map of keyboard modes to resource IDs. */
+ private static final SparseIntArray KEYBOARD_MODE_RES_IDS = new SparseIntArray();
+
+ static {
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_DATE, R.string.keyboard_mode_date);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_DATETIME, R.string.keyboard_mode_date_time);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_EMAIL, R.string.keyboard_mode_email);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_IM, R.string.keyboard_mode_im);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_NUMBER, R.string.keyboard_mode_number);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_PHONE, R.string.keyboard_mode_phone);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_TEXT, R.string.keyboard_mode_text);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_TIME, R.string.keyboard_mode_time);
+ KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_URL, R.string.keyboard_mode_url);
+ }
+
private InputMethodService mInputMethod;
private MainKeyboardView mView;
private AccessibilityEntityProvider mAccessibilityNodeProvider;
@@ -42,12 +60,11 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
private Key mLastHoverKey = null;
/**
- * Inset in pixels to look for keys when the user's finger exits the
- * keyboard area.
+ * Inset in pixels to look for keys when the user's finger exits the keyboard area.
*/
private int mEdgeSlop;
- public static void init(InputMethodService inputMethod) {
+ public static void init(final InputMethodService inputMethod) {
sInstance.initInternal(inputMethod);
}
@@ -59,7 +76,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
// Not publicly instantiable.
}
- private void initInternal(InputMethodService inputMethod) {
+ private void initInternal(final InputMethodService inputMethod) {
mInputMethod = inputMethod;
mEdgeSlop = inputMethod.getResources().getDimensionPixelSize(
R.dimen.accessibility_edge_slop);
@@ -70,61 +87,125 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
*
* @param view The view to wrap.
*/
- public void setView(MainKeyboardView view) {
+ public void setView(final MainKeyboardView view) {
if (view == null) {
// Ignore null views.
return;
}
-
mView = view;
// Ensure that the view has an accessibility delegate.
ViewCompat.setAccessibilityDelegate(view, this);
- if (mAccessibilityNodeProvider != null) {
- mAccessibilityNodeProvider.setView(view);
+ if (mAccessibilityNodeProvider == null) {
+ return;
}
+ mAccessibilityNodeProvider.setView(view);
}
- public void setKeyboard(Keyboard keyboard) {
+ /**
+ * Called when the keyboard layout changes.
+ * <p>
+ * <b>Note:</b> This method will be called even if accessibility is not
+ * enabled.
+ */
+ public void setKeyboard() {
if (mAccessibilityNodeProvider != null) {
- mAccessibilityNodeProvider.setKeyboard(keyboard);
+ mAccessibilityNodeProvider.setKeyboard();
+ }
+
+ // Since this method is called even when accessibility is off, make sure
+ // to check the state before announcing anything.
+ if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
+ announceKeyboardMode();
}
}
/**
- * Proxy method for View.getAccessibilityNodeProvider(). This method is
- * called in SDK version 15 and higher to obtain the virtual node hierarchy
- * provider.
+ * Called when the keyboard is hidden and accessibility is enabled.
+ */
+ public void onHideWindow() {
+ announceKeyboardHidden();
+ }
+
+ /**
+ * Announces which type of keyboard is being displayed. If the keyboard type
+ * is unknown, no announcement is made.
+ */
+ private void announceKeyboardMode() {
+ final Keyboard keyboard = mView.getKeyboard();
+ final int resId = KEYBOARD_MODE_RES_IDS.get(keyboard.mId.mMode);
+ if (resId == 0) {
+ return;
+ }
+
+ final Context context = mView.getContext();
+ final String keyboardMode = context.getString(resId);
+ final String text = context.getString(R.string.announce_keyboard_mode, keyboardMode);
+
+ sendWindowStateChanged(text);
+ }
+
+ /**
+ * Announces that the keyboard has been hidden.
+ */
+ private void announceKeyboardHidden() {
+ final Context context = mView.getContext();
+ final String text = context.getString(R.string.announce_keyboard_hidden);
+
+ sendWindowStateChanged(text);
+ }
+
+ /**
+ * Sends a window state change event with the specified text.
+ *
+ * @param text
+ */
+ private void sendWindowStateChanged(final String text) {
+ final AccessibilityEvent stateChange = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ mView.onInitializeAccessibilityEvent(stateChange);
+ stateChange.getText().add(text);
+ stateChange.setContentDescription(null);
+
+ final ViewParent parent = mView.getParent();
+ if (parent != null) {
+ parent.requestSendAccessibilityEvent(mView, stateChange);
+ }
+ }
+
+ /**
+ * Proxy method for View.getAccessibilityNodeProvider(). This method is called in SDK
+ * version 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) and higher to obtain the virtual
+ * node hierarchy provider.
*
* @return The accessibility node provider for the current keyboard.
*/
@Override
- public AccessibilityEntityProvider getAccessibilityNodeProvider(View host) {
+ public AccessibilityEntityProvider getAccessibilityNodeProvider(final View host) {
return getAccessibilityNodeProvider();
}
/**
- * Intercepts touch events before dispatch when touch exploration is turned
- * on in ICS and higher.
+ * Intercepts touch events before dispatch when touch exploration is turned on in ICS and
+ * higher.
*
* @param event The motion event being dispatched.
* @return {@code true} if the event is handled
*/
- public boolean dispatchTouchEvent(MotionEvent event) {
+ public boolean dispatchTouchEvent(final MotionEvent event) {
// To avoid accidental key presses during touch exploration, always drop
// touch events generated by the user.
return false;
}
/**
- * Receives hover events when touch exploration is turned on in SDK versions
- * ICS and higher.
+ * Receives hover events when touch exploration is turned on in SDK versions ICS and higher.
*
* @param event The hover event.
* @return {@code true} if the event is handled
*/
- public boolean dispatchHoverEvent(MotionEvent event, PointerTracker tracker) {
+ public boolean dispatchHoverEvent(final MotionEvent event, final PointerTracker tracker) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final Key previousKey = mLastHoverKey;
@@ -135,7 +216,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
} else {
key = null;
}
-
mLastHoverKey = key;
switch (event.getAction()) {
@@ -173,30 +253,29 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
}
/**
- * Utility method to determine whether the given point, in local
- * coordinates, is inside the view, where the area of the view is contracted
- * by the edge slop factor.
+ * Utility method to determine whether the given point, in local coordinates, is inside the
+ * view, where the area of the view is contracted by the edge slop factor.
*
* @param localX The local x-coordinate.
* @param localY The local y-coordinate.
*/
- private boolean pointInView(int localX, int localY) {
+ private boolean pointInView(final int localX, final int localY) {
return (localX >= mEdgeSlop) && (localY >= mEdgeSlop)
&& (localX < (mView.getWidth() - mEdgeSlop))
&& (localY < (mView.getHeight() - mEdgeSlop));
}
/**
- * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT
- * on the previous key, a HOVER_ENTER on the current key, and a HOVER_MOVE
- * on the current key.
+ * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT on the previous key,
+ * a HOVER_ENTER on the current key, and a HOVER_MOVE on the current key.
*
* @param currentKey The currently hovered key.
* @param previousKey The previously hovered key.
* @param event The event that triggered the transition.
* @return {@code true} if the event was handled.
*/
- private boolean onTransitionKey(Key currentKey, Key previousKey, MotionEvent event) {
+ private boolean onTransitionKey(final Key currentKey, final Key previousKey,
+ final MotionEvent event) {
final int savedAction = event.getAction();
event.setAction(MotionEvent.ACTION_HOVER_EXIT);
@@ -214,19 +293,18 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
}
/**
- * Handles a hover event on a key. If {@link Key} extended View, this would
- * be analogous to calling View.onHoverEvent(MotionEvent).
+ * Handles a hover event on a key. If {@link Key} extended View, this would be analogous to
+ * calling View.onHoverEvent(MotionEvent).
*
* @param key The currently hovered key.
* @param event The hover event.
* @return {@code true} if the event was handled.
*/
- private boolean onHoverKey(Key key, MotionEvent event) {
+ private boolean onHoverKey(final Key key, final MotionEvent event) {
// Null keys can't receive events.
if (key == null) {
return false;
}
-
final AccessibilityEntityProvider provider = getAccessibilityNodeProvider();
switch (event.getAction()) {
@@ -241,7 +319,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT);
break;
}
-
return true;
}
@@ -268,7 +345,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
default:
text = context.getText(R.string.spoken_description_shiftmode_off);
}
-
AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
}
@@ -307,7 +383,6 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
if (resId < 0) {
return;
}
-
final String text = context.getString(resId);
AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
}
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index 32618ad85..05d8269b7 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -26,6 +26,7 @@ import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import java.util.HashMap;
@@ -61,17 +62,19 @@ public final class KeyCodeDescriptionMapper {
mKeyLabelMap.put(":-)", R.string.spoken_description_smiley);
// Special non-character codes defined in Keyboard
- mKeyCodeMap.put(Keyboard.CODE_SPACE, R.string.spoken_description_space);
- mKeyCodeMap.put(Keyboard.CODE_DELETE, R.string.spoken_description_delete);
- mKeyCodeMap.put(Keyboard.CODE_ENTER, R.string.spoken_description_return);
- mKeyCodeMap.put(Keyboard.CODE_SETTINGS, R.string.spoken_description_settings);
- mKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift);
- mKeyCodeMap.put(Keyboard.CODE_SHORTCUT, R.string.spoken_description_mic);
- mKeyCodeMap.put(Keyboard.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol);
- mKeyCodeMap.put(Keyboard.CODE_TAB, R.string.spoken_description_tab);
- mKeyCodeMap.put(Keyboard.CODE_LANGUAGE_SWITCH, R.string.spoken_description_language_switch);
- mKeyCodeMap.put(Keyboard.CODE_ACTION_NEXT, R.string.spoken_description_action_next);
- mKeyCodeMap.put(Keyboard.CODE_ACTION_PREVIOUS, R.string.spoken_description_action_previous);
+ mKeyCodeMap.put(Constants.CODE_SPACE, R.string.spoken_description_space);
+ mKeyCodeMap.put(Constants.CODE_DELETE, R.string.spoken_description_delete);
+ mKeyCodeMap.put(Constants.CODE_ENTER, R.string.spoken_description_return);
+ mKeyCodeMap.put(Constants.CODE_SETTINGS, R.string.spoken_description_settings);
+ mKeyCodeMap.put(Constants.CODE_SHIFT, R.string.spoken_description_shift);
+ mKeyCodeMap.put(Constants.CODE_SHORTCUT, R.string.spoken_description_mic);
+ mKeyCodeMap.put(Constants.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol);
+ mKeyCodeMap.put(Constants.CODE_TAB, R.string.spoken_description_tab);
+ mKeyCodeMap.put(Constants.CODE_LANGUAGE_SWITCH,
+ R.string.spoken_description_language_switch);
+ mKeyCodeMap.put(Constants.CODE_ACTION_NEXT, R.string.spoken_description_action_next);
+ mKeyCodeMap.put(Constants.CODE_ACTION_PREVIOUS,
+ R.string.spoken_description_action_previous);
}
/**
@@ -90,24 +93,26 @@ public final class KeyCodeDescriptionMapper {
* @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
+ * @return a character sequence describing the action performed by pressing the key
*/
- public String getDescriptionForKey(Context context, Keyboard keyboard, Key key,
- boolean shouldObscure) {
+ public String getDescriptionForKey(final Context context, final Keyboard keyboard,
+ final Key key, final boolean shouldObscure) {
final int code = key.mCode;
- if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+ if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
final String description = getDescriptionForSwitchAlphaSymbol(context, keyboard);
- if (description != null)
+ if (description != null) {
return description;
+ }
}
- if (code == Keyboard.CODE_SHIFT) {
+ if (code == Constants.CODE_SHIFT) {
return getDescriptionForShiftKey(context, keyboard);
}
- if (code == Keyboard.CODE_ACTION_ENTER) {
+ if (code == Constants.CODE_ENTER) {
+ // The following function returns the correct description in all action and
+ // regular enter cases, taking care of all modes.
return getDescriptionForActionKey(context, keyboard, key);
}
@@ -121,10 +126,9 @@ public final class KeyCodeDescriptionMapper {
}
// Just attempt to speak the description.
- if (key.mCode != Keyboard.CODE_UNSPECIFIED) {
+ if (key.mCode != Constants.CODE_UNSPECIFIED) {
return getDescriptionForKeyCode(context, keyboard, key, shouldObscure);
}
-
return null;
}
@@ -135,10 +139,10 @@ public final class KeyCodeDescriptionMapper {
*
* @param context The package's context.
* @param keyboard The keyboard on which the key resides.
- * @return a character sequence describing the action performed by pressing
- * the key
+ * @return a character sequence describing the action performed by pressing the key
*/
- private String getDescriptionForSwitchAlphaSymbol(Context context, Keyboard keyboard) {
+ private String getDescriptionForSwitchAlphaSymbol(final Context context,
+ final Keyboard keyboard) {
final KeyboardId keyboardId = keyboard.mId;
final int elementId = keyboardId.mElementId;
final int resId;
@@ -165,7 +169,6 @@ public final class KeyCodeDescriptionMapper {
Log.e(TAG, "Missing description for keyboard element ID:" + elementId);
return null;
}
-
return context.getString(resId);
}
@@ -176,7 +179,7 @@ public final class KeyCodeDescriptionMapper {
* @param keyboard The keyboard on which the key resides.
* @return A context-sensitive description of the "Shift" key.
*/
- private String getDescriptionForShiftKey(Context context, Keyboard keyboard) {
+ private String getDescriptionForShiftKey(final Context context, final Keyboard keyboard) {
final KeyboardId keyboardId = keyboard.mId;
final int elementId = keyboardId.mElementId;
final int resId;
@@ -194,7 +197,6 @@ public final class KeyCodeDescriptionMapper {
default:
resId = R.string.spoken_description_shift;
}
-
return context.getString(resId);
}
@@ -204,12 +206,12 @@ public final class KeyCodeDescriptionMapper {
* @param context The package's context.
* @param keyboard The keyboard on which the key resides.
* @param key The key to describe.
- * @return Returns a context-sensitive description of the "Enter" action
- * key.
+ * @return Returns a context-sensitive description of the "Enter" action key.
*/
- private String getDescriptionForActionKey(Context context, Keyboard keyboard, Key key) {
+ private String getDescriptionForActionKey(final Context context, final Keyboard keyboard,
+ final Key key) {
final KeyboardId keyboardId = keyboard.mId;
- final int actionId = keyboardId.imeActionId();
+ final int actionId = keyboardId.imeAction();
final int resId;
// Always use the label, if available.
@@ -240,7 +242,6 @@ public final class KeyCodeDescriptionMapper {
default:
resId = R.string.spoken_description_return;
}
-
return context.getString(resId);
}
@@ -262,11 +263,10 @@ public final class KeyCodeDescriptionMapper {
* @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
+ * @return a character sequence describing the action performed by pressing the key
*/
- private String getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key,
- boolean shouldObscure) {
+ private String getDescriptionForKeyCode(final Context context, final Keyboard keyboard,
+ final Key key, final boolean shouldObscure) {
final int code = key.mCode;
// If the key description should be obscured, now is the time to do it.
@@ -274,15 +274,15 @@ public final class KeyCodeDescriptionMapper {
if (shouldObscure && isDefinedNonCtrl) {
return context.getString(OBSCURED_KEY_RES_ID);
}
-
if (mKeyCodeMap.indexOfKey(code) >= 0) {
return context.getString(mKeyCodeMap.get(code));
- } else if (isDefinedNonCtrl) {
+ }
+ if (isDefinedNonCtrl) {
return Character.toString((char) code);
- } else if (!TextUtils.isEmpty(key.mLabel)) {
+ }
+ if (!TextUtils.isEmpty(key.mLabel)) {
return key.mLabel;
- } else {
- return context.getString(R.string.spoken_description_unknown, code);
}
+ return context.getString(R.string.spoken_description_unknown, code);
}
}