Use sorted keys index as virtual view id
Change-Id: Id3f81de1edaacc06362b65aa7b68e9317e6596bd
This commit is contained in:
parent
b2de802de4
commit
9289260822
3 changed files with 73 additions and 66 deletions
|
@ -26,7 +26,6 @@ import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
|
||||||
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
|
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
@ -37,9 +36,10 @@ import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.keyboard.KeyboardView;
|
import com.android.inputmethod.keyboard.KeyboardView;
|
||||||
import com.android.inputmethod.latin.settings.Settings;
|
import com.android.inputmethod.latin.settings.Settings;
|
||||||
import com.android.inputmethod.latin.settings.SettingsValues;
|
import com.android.inputmethod.latin.settings.SettingsValues;
|
||||||
import com.android.inputmethod.latin.utils.CollectionUtils;
|
|
||||||
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
import com.android.inputmethod.latin.utils.CoordinateUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exposes a virtual view sub-tree for {@link KeyboardView} and generates
|
* Exposes a virtual view sub-tree for {@link KeyboardView} and generates
|
||||||
* {@link AccessibilityEvent}s for individual {@link Key}s.
|
* {@link AccessibilityEvent}s for individual {@link Key}s.
|
||||||
|
@ -58,9 +58,6 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper;
|
private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper;
|
||||||
private final AccessibilityUtils mAccessibilityUtils;
|
private final AccessibilityUtils mAccessibilityUtils;
|
||||||
|
|
||||||
/** A map of integer IDs to {@link Key}s. */
|
|
||||||
private final SparseArray<Key> mVirtualViewIdToKey = CollectionUtils.newSparseArray();
|
|
||||||
|
|
||||||
/** Temporary rect used to calculate in-screen bounds. */
|
/** Temporary rect used to calculate in-screen bounds. */
|
||||||
private final Rect mTempBoundsInScreen = new Rect();
|
private final Rect mTempBoundsInScreen = new Rect();
|
||||||
|
|
||||||
|
@ -73,6 +70,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
/** The current keyboard view. */
|
/** The current keyboard view. */
|
||||||
private KeyboardView mKeyboardView;
|
private KeyboardView mKeyboardView;
|
||||||
|
|
||||||
|
/** The current keyboard. */
|
||||||
|
private Keyboard mKeyboard;
|
||||||
|
|
||||||
public AccessibilityEntityProvider(final KeyboardView keyboardView,
|
public AccessibilityEntityProvider(final KeyboardView keyboardView,
|
||||||
final InputMethodService inputMethod) {
|
final InputMethodService inputMethod) {
|
||||||
mInputMethodService = inputMethod;
|
mInputMethodService = inputMethod;
|
||||||
|
@ -92,14 +92,43 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
|
|
||||||
// Since this class is constructed lazily, we might not get a subsequent
|
// Since this class is constructed lazily, we might not get a subsequent
|
||||||
// call to setKeyboard() and therefore need to call it now.
|
// call to setKeyboard() and therefore need to call it now.
|
||||||
setKeyboard();
|
setKeyboard(keyboardView.getKeyboard());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the keyboard represented by this node provider.
|
* Sets the keyboard represented by this node provider.
|
||||||
|
*
|
||||||
|
* @param keyboard The keyboard that is being set to the keyboard view.
|
||||||
*/
|
*/
|
||||||
public void setKeyboard() {
|
public void setKeyboard(final Keyboard keyboard) {
|
||||||
assignVirtualViewIds();
|
mKeyboard = keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Key getKeyOf(final int virtualViewId) {
|
||||||
|
if (mKeyboard == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final List<Key> sortedKeys = mKeyboard.getSortedKeys();
|
||||||
|
// Use a virtual view id as an index of the sorted keys list.
|
||||||
|
if (virtualViewId >= 0 && virtualViewId < sortedKeys.size()) {
|
||||||
|
return sortedKeys.get(virtualViewId);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getVirtualViewIdOf(final Key key) {
|
||||||
|
if (mKeyboard == null) {
|
||||||
|
return View.NO_ID;
|
||||||
|
}
|
||||||
|
final List<Key> sortedKeys = mKeyboard.getSortedKeys();
|
||||||
|
final int size = sortedKeys.size();
|
||||||
|
for (int index = 0; index < size; index++) {
|
||||||
|
if (sortedKeys.get(index) == key) {
|
||||||
|
// Use an index of the sorted keys list as a virtual view id.
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return View.NO_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,7 +141,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
* @see AccessibilityEvent
|
* @see AccessibilityEvent
|
||||||
*/
|
*/
|
||||||
public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) {
|
public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) {
|
||||||
final int virtualViewId = generateVirtualViewIdForKey(key);
|
final int virtualViewId = getVirtualViewIdOf(key);
|
||||||
final String keyDescription = getKeyDescription(key);
|
final String keyDescription = getKeyDescription(key);
|
||||||
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
|
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
|
||||||
event.setPackageName(mKeyboardView.getContext().getPackageName());
|
event.setPackageName(mKeyboardView.getContext().getPackageName());
|
||||||
|
@ -158,16 +187,21 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);
|
ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo);
|
||||||
|
|
||||||
// Add the virtual children of the root View.
|
// Add the virtual children of the root View.
|
||||||
final Keyboard keyboard = mKeyboardView.getKeyboard();
|
final List<Key> sortedKeys = mKeyboard.getSortedKeys();
|
||||||
for (final Key key : keyboard.getSortedKeys()) {
|
final int size = sortedKeys.size();
|
||||||
final int childVirtualViewId = generateVirtualViewIdForKey(key);
|
for (int index = 0; index < size; index++) {
|
||||||
rootInfo.addChild(mKeyboardView, childVirtualViewId);
|
final Key key = sortedKeys.get(index);
|
||||||
|
if (key.isSpacer()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Use an index of the sorted keys list as a virtual view id.
|
||||||
|
rootInfo.addChild(mKeyboardView, index);
|
||||||
}
|
}
|
||||||
return rootInfo;
|
return rootInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the view that corresponds to the given id.
|
// Find the key that corresponds to the given virtual view id.
|
||||||
final Key key = mVirtualViewIdToKey.get(virtualViewId);
|
final Key key = getKeyOf(virtualViewId);
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
|
Log.e(TAG, "Invalid virtual view ID: " + virtualViewId);
|
||||||
return null;
|
return null;
|
||||||
|
@ -226,7 +260,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
@Override
|
@Override
|
||||||
public boolean performAction(final int virtualViewId, final int action,
|
public boolean performAction(final int virtualViewId, final int action,
|
||||||
final Bundle arguments) {
|
final Bundle arguments) {
|
||||||
final Key key = mVirtualViewIdToKey.get(virtualViewId);
|
final Key key = getKeyOf(virtualViewId);
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +276,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
* @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(final Key key, final int action, final Bundle arguments) {
|
boolean performActionForKey(final Key key, final int action, final Bundle arguments) {
|
||||||
final int virtualViewId = generateVirtualViewIdForKey(key);
|
final int virtualViewId = getVirtualViewIdOf(key);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
|
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
|
||||||
|
@ -288,7 +322,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo);
|
final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo);
|
||||||
final SettingsValues currentSettings = Settings.getInstance().getCurrent();
|
final SettingsValues currentSettings = Settings.getInstance().getCurrent();
|
||||||
final String keyCodeDescription = mKeyCodeDescriptionMapper.getDescriptionForKey(
|
final String keyCodeDescription = mKeyCodeDescriptionMapper.getDescriptionForKey(
|
||||||
mKeyboardView.getContext(), mKeyboardView.getKeyboard(), key, shouldObscure);
|
mKeyboardView.getContext(), mKeyboard, key, shouldObscure);
|
||||||
if (currentSettings.isWordSeparator(key.getCode())) {
|
if (currentSettings.isWordSeparator(key.getCode())) {
|
||||||
return mAccessibilityUtils.getAutoCorrectionDescription(
|
return mAccessibilityUtils.getAutoCorrectionDescription(
|
||||||
keyCodeDescription, shouldObscure);
|
keyCodeDescription, shouldObscure);
|
||||||
|
@ -297,40 +331,10 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns virtual view IDs to keyboard keys and populates the related maps.
|
|
||||||
*/
|
|
||||||
private void assignVirtualViewIds() {
|
|
||||||
final Keyboard keyboard = mKeyboardView.getKeyboard();
|
|
||||||
if (keyboard == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mVirtualViewIdToKey.clear();
|
|
||||||
|
|
||||||
for (final Key key : keyboard.getSortedKeys()) {
|
|
||||||
final int virtualViewId = generateVirtualViewIdForKey(key);
|
|
||||||
mVirtualViewIdToKey.put(virtualViewId, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the parent's on-screen location.
|
* Updates the parent's on-screen location.
|
||||||
*/
|
*/
|
||||||
private void updateParentLocation() {
|
private void updateParentLocation() {
|
||||||
mKeyboardView.getLocationOnScreen(mParentLocation);
|
mKeyboardView.getLocationOnScreen(mParentLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a virtual view identifier for the given key. Returned
|
|
||||||
* identifiers are valid until the next global layout state change.
|
|
||||||
*
|
|
||||||
* @param key The key to identify.
|
|
||||||
* @return A virtual view identifier.
|
|
||||||
*/
|
|
||||||
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.
|
|
||||||
return ((0xFFFF & key.getX()) << (Integer.SIZE / 2)) | (0xFFFF & key.getY());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
|
|
||||||
private InputMethodService mInputMethod;
|
private InputMethodService mInputMethod;
|
||||||
private MainKeyboardView mView;
|
private MainKeyboardView mView;
|
||||||
|
private Keyboard mKeyboard;
|
||||||
private AccessibilityEntityProvider mAccessibilityNodeProvider;
|
private AccessibilityEntityProvider mAccessibilityNodeProvider;
|
||||||
|
|
||||||
private Key mLastHoverKey = null;
|
private Key mLastHoverKey = null;
|
||||||
|
@ -66,6 +67,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
|
|
||||||
/** The most recently set keyboard mode. */
|
/** The most recently set keyboard mode. */
|
||||||
private int mLastKeyboardMode;
|
private int mLastKeyboardMode;
|
||||||
|
private static final int NOT_A_KEYBOARD_MODE = -1;
|
||||||
|
|
||||||
public static void init(final InputMethodService inputMethod) {
|
public static void init(final InputMethodService inputMethod) {
|
||||||
sInstance.initInternal(inputMethod);
|
sInstance.initInternal(inputMethod);
|
||||||
|
@ -104,6 +106,10 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mAccessibilityNodeProvider.setView(view);
|
mAccessibilityNodeProvider.setView(view);
|
||||||
|
|
||||||
|
// Since this class is constructed lazily, we might not get a subsequent
|
||||||
|
// call to setKeyboard() and therefore need to call it now.
|
||||||
|
setKeyboard(view.getKeyboard());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,15 +117,17 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Note:</b> This method will be called even if accessibility is not
|
* <b>Note:</b> This method will be called even if accessibility is not
|
||||||
* enabled.
|
* enabled.
|
||||||
|
* @param keyboard The keyboard that is being set to the wrapping view.
|
||||||
*/
|
*/
|
||||||
public void setKeyboard() {
|
public void setKeyboard(final Keyboard keyboard) {
|
||||||
if (mView == null) {
|
if (keyboard == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mKeyboard = keyboard;
|
||||||
if (mAccessibilityNodeProvider != null) {
|
if (mAccessibilityNodeProvider != null) {
|
||||||
mAccessibilityNodeProvider.setKeyboard();
|
mAccessibilityNodeProvider.setKeyboard(keyboard);
|
||||||
}
|
}
|
||||||
final int keyboardMode = mView.getKeyboard().mId.mMode;
|
final int keyboardMode = keyboard.mId.mMode;
|
||||||
|
|
||||||
// Since this method is called even when accessibility is off, make sure
|
// Since this method is called even when accessibility is off, make sure
|
||||||
// to check the state before announcing anything. Also, don't announce
|
// to check the state before announcing anything. Also, don't announce
|
||||||
|
@ -139,7 +147,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
announceKeyboardHidden();
|
announceKeyboardHidden();
|
||||||
mLastKeyboardMode = -1;
|
mLastKeyboardMode = NOT_A_KEYBOARD_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,7 +156,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
*
|
*
|
||||||
* @param mode The new keyboard mode.
|
* @param mode The new keyboard mode.
|
||||||
*/
|
*/
|
||||||
private void announceKeyboardMode(int mode) {
|
private void announceKeyboardMode(final int mode) {
|
||||||
final int resId = KEYBOARD_MODE_RES_IDS.get(mode);
|
final int resId = KEYBOARD_MODE_RES_IDS.get(mode);
|
||||||
if (resId == 0) {
|
if (resId == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -329,12 +337,11 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
* Notifies the user of changes in the keyboard shift state.
|
* Notifies the user of changes in the keyboard shift state.
|
||||||
*/
|
*/
|
||||||
public void notifyShiftState() {
|
public void notifyShiftState() {
|
||||||
if (mView == null) {
|
if (mView == null || mKeyboard == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Keyboard keyboard = mView.getKeyboard();
|
final KeyboardId keyboardId = mKeyboard.mId;
|
||||||
final KeyboardId keyboardId = keyboard.mId;
|
|
||||||
final int elementId = keyboardId.mElementId;
|
final int elementId = keyboardId.mElementId;
|
||||||
final Context context = mView.getContext();
|
final Context context = mView.getContext();
|
||||||
final CharSequence text;
|
final CharSequence text;
|
||||||
|
@ -359,14 +366,13 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
* Notifies the user of changes in the keyboard symbols state.
|
* Notifies the user of changes in the keyboard symbols state.
|
||||||
*/
|
*/
|
||||||
public void notifySymbolsState() {
|
public void notifySymbolsState() {
|
||||||
if (mView == null) {
|
if (mView == null || mKeyboard == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Keyboard keyboard = mView.getKeyboard();
|
final KeyboardId keyboardId = mKeyboard.mId;
|
||||||
final Context context = mView.getContext();
|
|
||||||
final KeyboardId keyboardId = keyboard.mId;
|
|
||||||
final int elementId = keyboardId.mElementId;
|
final int elementId = keyboardId.mElementId;
|
||||||
|
final Context context = mView.getContext();
|
||||||
final int resId;
|
final int resId;
|
||||||
|
|
||||||
switch (elementId) {
|
switch (elementId) {
|
||||||
|
@ -388,12 +394,9 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
|
||||||
resId = R.string.spoken_description_mode_phone_shift;
|
resId = R.string.spoken_description_mode_phone_shift;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
resId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resId < 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String text = context.getString(resId);
|
final String text = context.getString(resId);
|
||||||
AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
|
AccessibilityUtils.getInstance().announceForAccessibility(mView, text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,7 +406,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
|
||||||
|
|
||||||
// This always needs to be set since the accessibility state can
|
// This always needs to be set since the accessibility state can
|
||||||
// potentially change without the keyboard being set again.
|
// potentially change without the keyboard being set again.
|
||||||
AccessibleKeyboardViewProxy.getInstance().setKeyboard();
|
AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue